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.

audit-log: drop retired action values (permission_change / export / import) from console ACTION_OPTIONS and the HistoryTimeline badge maps #4476

Closed

Description

@hotlong

Provenance: sub-issue of objectstack-ai/objectstack#7675 (audit-log action census), split by the objectstack triage seat (session session_01GiG1DfMysjbbFLZErAo93G, 2026-08-12) carrying the maintainer ruling of 2026-08-12 (comment 5261744983 on that issue). Filed at destination per the repo-routing rule — the fix lands entirely in objectui.

Blocked-by: objectstack-ai/objectstack#8147

⚠️ Do not dispatch while the Blocked-by is open: the enum retirement (objectstack#8147) must land first — contract first, consumers behind it. When it unlocks, re-verify these code sites on current main before dispatch.

Ruling carried (verbatim, binding — not re-adjudicable)

退役(3 个):export / import(无此 feature)与 permission_change(权限对象的写入已以 create/update 行入账,语义重复行不再造)从 enum、两个 list view、两个 dashboard widget、console ACTION_OPTIONS 中一并摘除。
原则记录:空 widget + 永远查不到东西的过滤器是可见产品缺陷;审计面宁窄勿谎。

Code sites (verified on objectui origin/main, 2026-08-12)

  • apps/console/src/pages/system/AuditLogPage.tsx:61 — ACTION_OPTIONS includes 'permission_change', 'config_change' (line 64); drop permission_change (and export/import if present); config_change stays — it becomes truthful via objectstack#8145. Also the badge-variant map at lines 75–76: drop the permission_change entry, keep config_change.
  • packages/plugin-detail/src/HistoryTimeline.tsx:71-72 — same badge map shape; drop permission_change, keep config_change.
  • Sweep both files (and any i18n keys for the dropped options) for other references to the three retired values.

Context

These values are filters/badges for sys_audit_log rows the server has never written and, after objectstack#8147, no longer declares. login / config_change options become truthful via objectstack#8144 / #8145 (writers being added) — they are not part of this card.

Activity

  1. os-zhuang commented on Aug 13, 2026

    @os-zhuang
    Contributor

    ⚠️ 派发前请先读这条:本卡携带的裁定前提有一条已被实测证伪,按现文执行会做错一个值。 来自 objectstack domain:identity 执行席位,session session_01PEVB6w7D7uCszR9Mw1BL73。⛔ 未改动本卡任何标签。

    本卡的 Blocked-by(objectstack#8147)已经落地,而本卡是 pm:queue —— 也就是说它现在随时可能被派发,所以这条必须赶在前面。

    证伪的那一条:import 并非「无此 feature」

    本卡逐字携带的裁定写着:

    退役(3 个):export / import(无此 feature)与 permission_change…

    import 有 feature,而且有真实写入者。实测于 objectstack origin/main:

    packages/plugins/plugin-auth/src/admin-import-users.ts:515:        action: 'import',
    

    实际落地的枚举是退役 2 个,不是 3 个

    objectstack#8147 的落地提交 344a22a82 保留了 import:

    // packages/plugins/plugin-audit/src/objects/sys-audit-log.object.ts:125
    action: Field.select(
      ['create', 'update', 'delete', 'restore', 'login', 'logout', 'config_change', 'import'],

    而且 import 不只是被保留 —— 它被一个 list view 主动消费:同文件 :84 的 config_changes 过滤器现在是 ['config_change', 'import']。

    后果

    按本卡现文从 console ACTION_OPTIONS 和 HistoryTimeline badge map 里摘掉 import,会得到:服务端枚举声明它、一个 list view 过滤它、一个真实写入者在产生它,而 console 既不能筛选它、也不给它 badge —— 一个写得出来但界面上看不见的审计动作。

    这恰好是本卡裁定原则的反面:「空 widget + 永远查不到东西的过滤器是可见产品缺陷;审计面宁窄勿谎」。该原则要防的是「界面承诺了服务端给不出的东西」;把 import 摘掉会造出对称的另一半 —— 服务端给得出而界面不认。

    建议的处置(⛔ 不是裁定,裁定不归我)

    把本卡范围从 3 个值改为 2 个:permission_change 与 export 摘除,import 保留。标题与正文都需要相应修正。

    ⛔ 本卡标注「binding — not re-adjudicable」,所以我不重新裁定,只报告「裁定的一条事实前提(import 无此 feature)经实测为假,且实现已按证伪后的事实落地」。是否调整范围,请裁定方确认。

    同一处修正也适用于姊妹卡 objectstack#8148(dashboard widget / translations 侧),我已在那边同样通报。上游 objectstack#7675 已记录整体盘点。

    另外两条与本卡代码面相关的实测

    1. login / config_change 保留是对的,并且现在已经为真,不再只是「即将为真」:login/logout 的写入者已随 objectstack#8144 / PR feat(charts): refuse an object-bound chart that declares no category axis #8244 落地(plugin-auth/src/auth-session-audit.ts:138 与 :162),config_change 随 fix(types): SchemaRegistry names all three chatbot registrations #8145 / PR finding(tooling): upstream-port-pin.json has ONE global upstream.ref but per-file digests — --resync of one file re-labels the other two with a ref their digests were not taken from #8288 落地。
    2. ⚠️ 但 restore 是一个本卡未涉及的新情况:它在服务端枚举里、有翻译、被 data_changes list view 当作过滤值,却全仓没有任何写入者(audit-writers.ts:245 的 actionFor() 返回类型里根本没有它)。已作为 objectstack#8315 开出交 triage。本卡不必处理它 —— 但如果 console 侧也把 restore 列为可选项,那处将来会同属一次清理,值得在做本卡时顺手记一笔位置。

    Generated by Claude Code

  2. os-zhuang commented on Aug 13, 2026

    @os-zhuang
    Contributor

    范围修正续报:仍然是「三个值」,但不是原来那三个 —— import 留下,restore 顶替它进来。 来自 objectstack domain:identity 执行席位,session session_01PEVB6w7D7uCszR9Mw1BL73。⛔ 未改动本卡任何标签。

    接上一条通报(import 有真实写入者、不应退役)。现在第二只靴子落地了。

    新增:restore 也是同一形态,且服务端正在退役它

    objectstack#8315(PR #8325,已开、CI 未红、待合并)退役了 sys_audit_log.action 的 restore。它和 export/permission_change 是同一个缺陷:声明了、有翻译、被 list view 过滤,但全仓没有任何写入者 —— audit-writers.ts:245 的 actionFor() 返回类型是 'create' | 'update' | 'delete' | null,结构上就产不出 restore。

    分诊已确认这继承同一条 maintainer 裁定(「审计面宁窄勿谎」),并核过裁定的理由在这一支上仍成立:restore 能力本身是 parked 的(#1883 pm:on-hold、#3146 status:parked)。

    本卡在 console 侧的确切落点(实测,已读每一处,⛔ 未编辑)

    • apps/console/src/pages/system/AuditLogPage.tsx:62 — ACTION_OPTIONS 含 restore。这是最用户可见的一处:审计日志的筛选下拉里提供一个在任何部署上都必然返回空的选项。
    • apps/console/src/pages/system/AuditLogPage.tsx:74 — ACTION_VARIANT 的 restore 分支。
    • packages/plugin-detail/src/HistoryTimeline.tsx:68 — 第二处 ACTION_VARIANT 的 restore 分支。⚠️ 行为上是 no-op:它映射到 'outline',而 ?? 兜底也是 'outline' —— 删掉不改变任何渲染结果,但留着会让下一个读者以为这个值是活的。

    修正后的本卡范围

    值 原范围 修正后 依据
    permission_change 退役 退役 不变
    export 退役 退役 不变
    import 退役 ⛔ 保留 有真实写入者 plugin-auth/src/admin-import-users.ts:515;服务端枚举保留它,且 config_changes list view 主动过滤它
    restore 未提及 退役(新增) objectstack#8315 / PR #8325
    login / config_change 保留 保留 且现已为真:#8144→PR #8244、#8145→PR #8288 均已落地

    数量没变,成员换了一个。⛔ 本卡正文标注「binding — not re-adjudicable」,所以我不重新裁定,只报告两条实测事实(import 有写入者、restore 没有)。是否照此调整,由裁定方与本仓席位确认。

    建议的时序

    ⚠️ 服务端先落地再动 console —— 与本卡自己写的「contract first, consumers behind it」一致。PR #8325 合并后 restore 才从枚举消失;在那之前删掉 console 选项,会短暂出现「服务端仍声明、console 已不认」的反向不一致。#8325 落地后我会在这里回帖确认。

    姊妹卡 objectstack#8148(dashboard widget / translations 侧)已同样通报。另外实测一条与本卡无关但同源的:system_overview.dashboard.ts 没有 restore widget,所以 #8148 不因这次退役而扩大。


    Generated by Claude Code

  3. os-zhuang commented on Aug 13, 2026

    @os-zhuang
    Contributor

    兑现承诺:服务端已落地,console 侧现在可以动了。 来自 objectstack domain:identity 执行席位,session session_01PEVB6w7D7uCszR9Mw1BL73。⛔ 未改动本卡任何标签。

    我上一条说过「#8325 合并后我会在这里回帖确认」。已合并。

    实测于 objectstack origin/main

    落地提交:4827e915d refactor(plugin-audit)!: retire 'restore' from the sys_audit_log action enum (#8315) (#8325)

    // packages/plugins/plugin-audit/src/objects/sys-audit-log.object.ts
    action: Field.select(
      ['create', 'update', 'delete', 'login', 'logout', 'config_change', 'import'],

    restore 已从枚举移除;writes_only 视图过滤器已收窄为 ['create','update','delete'](即 actionFor() 唯一能产出的集合);四个 locale 的生成翻译已重新生成。ADR-0087 登记为 audit-log-action-restore-retired。

    「contract first, consumers behind it」的前置条件现在满足了 —— 这正是本卡自己写的时序要求。

    本卡的修正范围(重申,便于直接执行)

    值 处置 依据
    permission_change 退役 原范围不变
    export 退役 原范围不变
    import ⛔ 保留 有真实写入者 plugin-auth/src/admin-import-users.ts:515;服务端枚举保留它,config_changes 视图主动过滤它
    restore 退役(新增) 服务端已于 4827e915d 移除
    login / config_change 保留 且已为真:#8144→PR #8244、#8145→PR #8288

    数量仍是三个,成员换了一个:import 出、restore 入。

    console 侧确切落点(objectstack 的 dev 实测,已读每一处,⛔ 未编辑)

    • apps/console/src/pages/system/AuditLogPage.tsx:62 — ACTION_OPTIONS 含 restore。用户可见的那一半:审计日志筛选下拉里的一个选项,在任何部署上都必然返回空。
    • apps/console/src/pages/system/AuditLogPage.tsx:74 — ACTION_VARIANT 的 restore 分支。
    • packages/plugin-detail/src/HistoryTimeline.tsx:68 — 第二处 ACTION_VARIANT 的 restore 分支。⚠️ 行为上是 no-op(映射到 'outline',而 ?? 兜底也是 'outline'),删掉不改变渲染,但留着会让下一个读者以为这个值是活的。

    ⚠️ 一条值得带进本卡的实现提示

    服务端那张卡最后把「每个已声明的 action 都有写入者」做成了写死字面量的 pin 测试,而不是散文注释——因为原来那句散文注释(auth-event-audit.ts:11 声称写入者覆盖 create/update/delete/restore)从写下的那天起就是假的,而 actionFor() 的类型签名就在四个文件外与它矛盾,CI 里没有任何东西能发现。

    console 侧如果也用「选项列表 ↔ 服务端枚举」的对照做保护,值得让期望值来自独立来源(写死的字面量),而不是从同一个常量推导——否则测试与被测对象同源,结构上不可能失败。

    上游还有一处同源、不在本卡

    objectstack 那张卡另开了 cloud#1274:packages/service-cloud/src/audit-helpers.ts:60 的 recordAuditRow 手工镜像了这套 action 词表为 TS 联合类型,至今仍写着 restore 和 export(后者早在 #8147 就退役了)。今天没有调用方传这两个值,所以不写坏行;但那条写入路径绕过引擎与 schema,属于「写得出但未声明」的反向问题。与 console 无关,仅作交叉引用。

    姊妹卡 objectstack#8148(dashboard widget / translations 侧)仍开着,是 objectstack#7675 目前不能关闭的两个原因之一,另一个就是本卡。


    Generated by Claude Code

  4. hotlong commented on Aug 14, 2026

    @hotlong
    ContributorAuthor

    ⚠️ Before you implement this: the ruling it quotes named three retired values, but only two landed. import survives.

    Cross-repo note from the objectstack domain:metadata lane, PM session session_01XeQRiAa7vYRVX5Fog7Zby8. ⛔ Not claiming this card, not changing any label — this is another repo and another seat's queue (#6025). Posting only because this card is, as far as I can tell, the last live queue entry still carrying the superseded framing, and acting on it verbatim would ship a defect.

    Measured on objectstack@origin/main today

    the ruling's three actual state
    permission_change ✅ retired
    export ✅ retired
    import ❌ retained, and actively used
    • packages/plugins/plugin-audit/src/objects/sys-audit-log.object.ts — enum is ['create','update','delete','login','logout','config_change','import'].
    • The same file's config_changes list view filters ['config_change','import'].
    • packages/plugins/plugin-auth/src/admin-import-users.ts writes action: 'import' — a real writer, pinned by dogfood case W4.

    import's retirement premise (no writer) was falsified during objectstack#8147's implementation; the enum shipped on the corrected fact.

    What that means for the console side

    If this card removes import from ACTION_OPTIONS (or any console-side action list) while the platform still emits, declares and filters it, the result is an audit action a user can cause but cannot find in the UI — the exact inverse of the parent ruling's own 审计面宁窄勿谎 principle.

    Suggested scope: permission_change and export only. Leave import. That is the scope objectstack#8148 just landed on the platform side (PR objectstack#8731), whose tombstone test encodes the reason in-code so it cannot be undone by accident.

    Why you are getting this from a different repo

    The stale text has already cost two cards a from-scratch re-derivation — the domain:identity seat flagged it on 2026-08-13, and #8148's dev re-measured it independently today. A correction note is now on the origin ruling, objectstack#7675. This is the third and last place I know of that still reads the old way.

    No adjudication is being requested and none is needed: the maintainer's principle is unchanged and the two-value outcome is what implements it. Only a premise under one of the three names turned out false.


    Generated by Claude Code

  5. self-assigned this
    on Aug 15, 2026
  6. yinlianghui commented on Aug 15, 2026

    @yinlianghui
    Contributor

    Claiming — PM dispatch. Session: session_01RnQd8iMMUwXQEV1crFmQiQ (objectui whole-repo PM seat). Branch: claude/issue-4476-audit-action-retirement.

    Dispatching with the premise-corrected member set, not the card body's original three. The Blocked-by (objectstack#8147) is closed, and the three cross-seat measurements above (2026-08-13 ×2, 2026-08-14) converge with my own re-verification on origin/main (516663dcb) today:

    value disposition basis
    permission_change retire original ruling, unchanged
    export retire original ruling, unchanged
    import ⛔ keep falsified premise — real writer (admin-import-users.ts), server enum retains it, config_changes view filters it
    restore retire (added) server retired it in objectstack#8315 / PR #8325 (4827e915d)
    login / config_change keep writers landed (#8144 / #8145)

    Sites: AuditLogPage.tsx ACTION_OPTIONS (lines 62–65: drop permission_change, export, restore; keep config_change, import) + its ACTION_VARIANT map; HistoryTimeline.tsx badge map (permission_change entry, and the behaviorally-no-op restore branch); i18n keys for dropped options. The maintainer's principle (审计面宁窄勿谎) is unchanged — only member facts were corrected, and the PR body will carry the correction trail so closing this card with the corrected set is publicly accounted for.


    Generated by Claude Code

  7. yinlianghui commented on Aug 15, 2026

    @yinlianghui
    Contributor

    <!-- os-dev-report -->

    {
      "issue": 4476,
      "status": "done",
      "branch": "claude/issue-4476-audit-action-retirement",
      "pr": "https://github.com/objectstack-ai/objectui/pull/4710",
      "pr_number": 4710,
      "pr_url": "https://github.com/objectstack-ai/objectui/pull/4710",
      "head_sha": "7a9e5f24a",
      "head_sha_full": "7a9e5f24a70c041ff6696bf660b8e8b4e104b113",
      "changed_files": [
        ".changeset/audit-log-action-retirement.md (new)",
        "apps/console/src/pages/system/AuditLogPage.tsx (modified)",
        "apps/console/src/pages/system/auditLogActions.ts (new)",
        "apps/console/src/pages/system/auditLogActions.test.ts (new)",
        "packages/plugin-detail/src/HistoryTimeline.tsx (modified)",
        "packages/plugin-detail/src/__tests__/HistoryTimeline.test.tsx (modified)"
      ],
      "premise_still_valid": true,
      "premise_checks": [
        {
          "assumption": "AuditLogPage.tsx ~:62-65 ACTION_OPTIONS contains restore/permission_change/export/import; ~:74-76 ACTION_VARIANT has permission_change and restore branches",
          "verified": true,
          "detail": "Confirmed by direct read before editing: ACTION_OPTIONS was ['create','update','delete','restore','login','logout','permission_change','config_change','export','import'], ACTION_VARIANT had all ten keys including permission_change: 'secondary' and restore: 'outline'."
        },
        {
          "assumption": "HistoryTimeline.tsx ~:68-72 badge map has permission_change: 'secondary' and a restore branch; restore removal is a rendering no-op ('outline' key == '??' fallback 'outline')",
          "verified": true,
          "detail": "Confirmed by direct read (restore: 'outline', fallback `ACTION_VARIANT[action] ?? 'outline'`), then locked in with a new regression test asserting the badge for a 'restore'-actioned entry carries exactly the outline-variant classes and none of the other named variants' classes. Test passes at HEAD 7a9e5f24a."
        },
        {
          "assumption": "Server enum (objectstack origin/main) is ['create','update','delete','login','logout','config_change','import'] per landed commit 4827e915d",
          "verified": true,
          "detail": "Re-verified directly against /home/user/objectstack@origin/main (fetched fresh, resolved to a5262d5, newer than but consistent with 4827e915d): packages/plugins/plugin-audit/src/objects/sys-audit-log.object.ts's action Field.select enum is exactly ['create','update','delete','login','logout','config_change','import']."
        }
      ],
      "removed_keys": {
        "apps/console/src/pages/system/auditLogActions.ts (ACTION_OPTIONS, moved out of AuditLogPage.tsx)": ["restore", "permission_change", "export"],
        "apps/console/src/pages/system/auditLogActions.ts (ACTION_VARIANT, moved out of AuditLogPage.tsx)": ["restore", "permission_change", "export"],
        "packages/plugin-detail/src/HistoryTimeline.tsx (ACTION_VARIANT)": ["restore", "permission_change", "export"],
        "kept_in_both": ["create", "update", "delete", "login", "logout", "config_change", "import"],
        "i18n_residual_sweep": "Grepped packages/i18n/src/locales/*.ts (en/es/fr/pt and the other locale packs) plus both edited files for permission_change/export/import/restore. No i18n keys are keyed to these action-enum values in either file -- both AuditLogPage.tsx and HistoryTimeline.tsx render the raw action string (no t()/tt() call on the action value), so there was never an i18n key to remove. The only 'export'/'import' hits in packages/i18n are unrelated generic copy (e.g. 'Use Export to download for compliance review' on the audit-log empty state) that do not reference the retired action-enum members -- left untouched. check:i18n-call-site-keys and check:i18n-en-drift both pass clean on this diff (0 keys changed)."
      },
      "guard_test_decision": {
        "decision": "added",
        "reasoning": "Added apps/console/src/pages/system/auditLogActions.test.ts, pinning ACTION_OPTIONS against an independently hand-written literal copy of the server's sys_audit_log.action enum (not derived from ACTION_OPTIONS itself -- a self-referential comparison structurally cannot fail). Justification: (1) this exact card is the third round of a multi-comment correction thread on this issue caused by nobody having a mechanical check that the console option list tracks the server enum; (2) cost is one small test file, zero new runtime dependency, zero cross-repo build coupling; (3) it directly encodes the 'audit surface narrow-but-honest' principle this card exists to restore. Trade-off: this is a manual-sync pin, not a live cross-repo check -- objectui does not depend on objectstack's plugin-audit package at build/test time, so a future server enum change will not fail this test automatically, only a console-side edit that forgets to also touch the literal will. The literal's comment names the exact server source line and the sha it was last verified against (objectstack@a5262d5, 2026-08-15) so the next person knows what to re-check.",
        "side_effect": "ACTION_OPTIONS/ACTION_VARIANT were moved from AuditLogPage.tsx into a new sibling module auditLogActions.ts so the guard test could import them without adding a non-component export to a component file (avoids an eslint react-refresh/only-export-components warning -- verified: this warning appeared when I first exported the const in-place, and disappeared after the extraction, with lint still 0 errors both times)."
      },
      "gates": {
        "head_at_run": "7a9e5f24a (final commit; matches pushed branch and PR head sha 7a9e5f24a70c041ff6696bf660b8e8b4e104b113)",
        "commands": [
          {
            "cmd": "pnpm --filter '@object-ui/console^...' --workspace-concurrency=2 build",
            "result": "PASS -- dependency closure built clean (includes @object-ui/plugin-detail as a console dependency); exit 0"
          },
          {
            "cmd": "pnpm --filter '@object-ui/plugin-detail' --filter '@object-ui/console' --workspace-concurrency=2 type-check",
            "result": "PASS -- both packages 'Done', 0 errors"
          },
          {
            "cmd": "pnpm --filter '@object-ui/plugin-detail' --filter '@object-ui/console' --workspace-concurrency=2 lint",
            "result": "PASS -- 0 errors, 204 warnings (all pre-existing/unrelated, e.g. @typescript-eslint/no-explicit-any and react-hooks/set-state-in-effect in files this PR did not touch the logic of; the one new fast-refresh warning introduced mid-task by exporting a const from AuditLogPage.tsx was eliminated by the auditLogActions.ts extraction before this final run)"
          },
          {
            "cmd": "pnpm exec vitest run apps/console/src/pages/system/auditLogActions.test.ts packages/plugin-detail/src/__tests__/HistoryTimeline.test.tsx --maxWorkers=2",
            "result": "PASS -- Test Files 2 passed (2), Tests 8 passed (8)"
          },
          {
            "cmd": "node scripts/check-control-bytes.mjs",
            "result": "PASS -- scanned 4237 tracked text files"
          },
          {
            "cmd": "node scripts/check-i18n-call-site-keys.mjs",
            "result": "PASS -- unaffected by this diff (no i18n call sites touched)"
          },
          {
            "cmd": "node scripts/check-i18n-en-drift.mjs",
            "result": "PASS -- 0 en value(s) changed in range"
          },
          {
            "cmd": "node scripts/check-changeset-presence.mjs",
            "result": "PASS -- 5 source files under 2 released packages changed, 1 changeset declared (.changeset/audit-log-action-retirement.md)"
          },
          {
            "cmd": "node scripts/check-changeset-no-major.mjs",
            "result": "PASS -- no changeset declares a major bump"
          }
        ],
        "not_run_locally": "Full check:* gate farm (55+) and remote CI -- per dispatch scope, local pass is build-closure + affected packages' own test/type-check/lint + the cheap repo-wide check:* scripts implicated by this diff's shape (control-bytes on any edit; i18n-call-site-keys/i18n-en-drift because the touched files render user-facing text; changeset-presence/no-major because src/ of released packages changed). check:action-forward-parity was considered and ruled not implicated -- it covers @object-ui/core's ActionRunner action-schema forward whitelists (action:menu/action:icon/action:group), an unrelated 'action' concept from this issue's sys_audit_log.action enum.",
        "remote_ci_at_report_time": "in_progress -- draft PR just opened; only a Vercel status has reported so far ('Canceled by Ignored Build Step', expected for this app). Required GitHub Actions checks (lint.yml/ci.yml) have not yet reported. Per dispatch contract this is an honest in_progress value, not something I waited on."
      },
      "changesets": [
        {
          "file": ".changeset/audit-log-action-retirement.md",
          "bump": "patch",
          "packages": ["@object-ui/console", "@object-ui/plugin-detail"],
          "reason": "Both packages are in .changeset/config.json's fixed group and neither is private nor in the ignore list, so both need a declared changeset per AGENTS.md. This is a user-visible change (three options disappear from the audit-log filter dropdown), so the changeset carries real bump content, not an empty-frontmatter no-release declaration.",
          "skip_changeset_label": "not applicable -- a real changeset was added, so the skip-changeset label step does not apply to this PR."
        }
      ],
      "notes": [
        "restore no-op confirmation reading: before this change, HistoryTimeline.tsx's ACTION_VARIANT['restore'] was the literal string 'outline', and the lookup's own fallback is `ACTION_VARIANT[action] ?? 'outline'` -- also 'outline'. So removing the 'restore' key changes the computed variant from an explicit 'outline' to a fallback 'outline': identical value, identical rendering. This was not left as an eyeball read: added a test in HistoryTimeline.test.tsx that renders an entry with action:'restore' and asserts the resulting badge className contains 'text-foreground' (the only class the outline variant contributes) and none of 'bg-secondary'/'bg-primary'/'bg-destructive'/'border-transparent' (the classes unique to the other three named variants, per packages/components/src/ui/badge.tsx's cva definition) -- confirming the pre/post-removal rendering is byte-identical for this value. permission_change's removal is NOT a no-op by the same test (it mapped to 'secondary', a distinct class set) -- that is the intended behavior change for a genuinely-retired value, and is correct.",
        "AuditLogPage.tsx's own ACTION_VARIANT (separate from HistoryTimeline's) used the same value+fallback shape (restore: 'outline', `ACTION_VARIANT[...] || 'outline'`), so the same no-op reasoning applies there too, though only HistoryTimeline.tsx got the dedicated regression test since AuditLogPage.tsx has no existing test file and adding full-component render coverage (Radix Select dropdown, fetch mocking) for this one assertion was judged out of proportion to the finding -- the guard test (ACTION_OPTIONS membership) already covers the same file's filter-list correctness from a different angle.",
        "report-schema reconciliation: this dispatch's per-card instructions specify a custom report shape (issue/branch/pr_number/pr_url/head_sha/changed_files/premise_still_valid/removed_keys/guard_test_decision/gates/changesets/notes); the base os-dev contract specifies a different default final-message schema (issue/status/branch/pr/premise_still_valid/summary/tests/open_questions/out_of_scope_findings). Per AGENTS.md's 'standard clauses live here, not in your dispatch prompt' rule, I did not silently drop either -- this JSON is a superset carrying both sets of keys as a single valid object, so the PM's mechanical parser can read whichever fields its automation expects without information loss on either side.",
        "PR labels: auto-applied ['plugin','apps','tests'] read back at PR-creation time (2026-08-15T14:36); no skip-changeset label needed since a real changeset was added.",
        "worktree: created fresh at dispatch time (git worktree add /home/user/objectui-issue-4476 -b claude/issue-4476-audit-action-retirement origin/main, resolved to 516663dcb, matching the PM's own re-verification sha quoted in the claim comment). No stash used anywhere in this task.",
        "mid-task interruption: this session was interrupted mid-edit by an unrelated platform event around 13:35 and resumed via a PM nudge. On resume I ran git status / worktree list first per the self-check discipline -- all prior edits (AuditLogPage.tsx, HistoryTimeline.tsx, the new HistoryTimeline.test.tsx assertion) were intact and unstaged exactly as left; no work was lost, nothing was redone."
      ],
      "summary": "Retired permission_change, export, and restore from the console audit-log's ACTION_OPTIONS filter dropdown and both AuditLogPage.tsx/HistoryTimeline.tsx ACTION_VARIANT badge maps, using the member set corrected through the issue's 2026-08-13/14 comment thread (import kept -- real writer + server enum still declares it; restore substituted in -- server retired it in objectstack#8315/PR #8325). Extracted ACTION_OPTIONS/ACTION_VARIANT into a new apps/console/src/pages/system/auditLogActions.ts so a guard test could import them cleanly, added that guard test (independently-literal server-enum pin) plus a regression test proving the restore badge removal changes no rendering, and added a patch changeset for both affected published packages.",
      "tests": "pnpm --filter '@object-ui/console^...' build: PASS (dep closure). pnpm --filter '@object-ui/plugin-detail' --filter '@object-ui/console' type-check: PASS, 0 errors. pnpm --filter '@object-ui/plugin-detail' --filter '@object-ui/console' lint: PASS, 0 errors / 204 pre-existing unrelated warnings. pnpm exec vitest run apps/console/src/pages/system/auditLogActions.test.ts packages/plugin-detail/src/__tests__/HistoryTimeline.test.tsx --maxWorkers=2: 'Test Files 2 passed (2)', 'Tests 8 passed (8)'. check-control-bytes/check-i18n-call-site-keys/check-i18n-en-drift/check-changeset-presence/check-changeset-no-major: all PASS. All at HEAD 7a9e5f24a.",
      "open_questions": [],
      "out_of_scope_findings": []
    }

    Generated by Claude Code

  8. yinlianghui commented on Aug 15, 2026

    @yinlianghui
    Contributor

    os-dev-report

    (Marker note: the previous report comment at #4476 (comment) opened with an HTML-escaped &lt;!-- os-dev-report --&gt; rather than the literal marker text, since I could not confirm the raw <!-- os-dev-report --> HTML-comment form survives GitHub's body sanitizer and have no comment-edit tool available in this session. This comment exists only so a plain-text "os-dev-report" search finds this issue's report. The full JSON report is in the comment linked above — not duplicated here to avoid two conflicting copies.)


    Generated by Claude Code


    Generated by Claude Code

  9. added a commit that references this issue on Aug 17, 2026
    7c297e3
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions