Skip to content

decision(plugin-auth): sys_audit_log rows the admin identity endpoints wrote before #21174's fix still carry user-field values in free metadata. Scrub them with a one-time migration, or leave the append-only ledger untouched? #21198

Description

@objectstack-fleet

Ruled: 5942375063 · letter 甲 · 2026-10-01T23:03Z

立卡门 ②:只有维护者能做的决定(改写一张 append-only 的合规表)
动手的读者:维护者裁甲或乙;若裁乙,domain:services seat 2(#21118)把迁移派给一名 os-dev,由 PR 落在 plugin-auth
查重:mcp__github__search_issues "scrub existing audit log rows migration rewrite ledger metadata legacy values",6 条命中(含 closed),全部不是本题。最近的是 #21175(读侧父记录门,不涉及存量改写)和 #8147(action 枚举退役)
⚠️ 安全类卡:只写类别与位置,不写复现

维护者速读

#21174(PR #21195)修的是生产端:从这次发布开始,plugin-auth 的管理员建用户 / 设密码两个入口写的显式账本行,metadata 里只放管理员的决定,不再复制写进用户字段的值。可是升级前写下的那些行,metadata 里还是那份副本。只要读者持有账本授权,就能读到它们,包括数据面对这些字段正在屏蔽的读者。

分诊已经排除了读时过滤(5932908541:在自由 metadata 上再推导一遍遮罩,等于造第二套遮罩)。所以存量行只剩两条路:原样保留,或者一次性迁移把它们洗掉。账本是 append-only 的合规表,改不改写它属于安全边界,席位不能代决。

你要做的(一个动作): 回复 甲 / 乙。

事实(类别级)

选项

选项 做什么 代价
甲 原样保留 零成本;但已测到的泄露对每一条升级前的行无限期存在
乙(推荐) 写一个由生产端(plugin-auth)拥有的一次性迁移:只处理这两个事件的显式行,删掉不在封闭决定集里的 metadata 键,其余列不动 静态数据也闭合了;要改写 append-only 表,一次性,键集是封闭声明而不是启发式判断;按惯例在 sys_migration 留收据
丙 读时过滤这些旧键 分诊已排除(第二套遮罩),而且落在 plugin-audit,不在本车道范围。列出来只是为了完整

四维

关联


Generated by Claude Code · domain:services seat 2 · session_01DiCSbmJrkzNhuEAier4VoJ · https://claude.ai/code/session_01DiCSbmJrkzNhuEAier4VoJ

Activity

  1. objectstack-fleet commented on Oct 1, 2026

    @objectstack-fleet
    ContributorAuthor

    更正:本卡的推荐由乙改为甲 · domain:services seat 2 (#21118) · session_01DiCSbmJrkzNhuEAier4VoJ · 2026-10-01T15:55Z

    立卡时本席漏读了一条直接适用的维护者先例。现在补上,推荐随之改变。

    先例(Governing text): #20790 的 Q1 = B(5909514730,维护者「20790 同意」):

    "Q1 = B. Rotate, don't scrub. … History rows and audit snapshots stay append-only. ⛔ No rewrite of history or audit tables."

    那张卡问的是同一个问题:一项敏感值在修复前已经落进审计快照,要不要改写审计表把它擦掉。维护者裁的是不改写。

    和本卡的差别(如实呈现): #20790 的密钥可以轮换,旧值轮换后就作废了。本卡存量行里的值是用户字段值(标识、电话、角色标量、强制改密标志),没有"轮换"这个动作:换了号码,旧号码依然是一条真实信息。所以对本卡来说,选甲意味着已测到的泄露对存量行永久存在,而不只是"存在到轮换为止"。

    修订后的推荐:甲(不改写),与先例一致。

    • ① 长远:先例对 ① 的读法是"审计只追加、写入点唯一"。本卡沿用,不为一类旧行开改写口子。
    • ② 拉动:受影响的只有升级前用过管理员建用户入口的部署,而且读者必须持有账本授权。
    • ③④ 不翻转。
    • 如果您认为"值不可轮换"足以构成例外,那就选乙。乙的形态不变:由生产端拥有的一次性迁移,只删封闭决定集之外的键。

    你要做的(一个动作)不变: 回复 甲 / 乙。


    Generated by Claude Code

  2. objectstack-fleet commented on Oct 1, 2026

    @objectstack-fleet
    ContributorAuthor

    Ruling: batch #264 item 3 · letter 甲 · maintainer 「同意264」 2026-10-01T23:02Z

    Director seat, summon #32, session_016tKoy8NJa35Yih1FdzrVmn. Written as objectstack-fleet[bot] through the relay. ⛔ Classes and positions only.

    • How it was ruled. Batch 🔗 Broken links detected in documentation #264 was presented in the live director chat. This card was item 3, director recommendation 甲, fallback 乙. The seat's own corrected recommendation (5935199195) was also 甲. The maintainer answered the batch as presented: 「同意264」.
    • Freshness gate: no comment after 5935199195.

    The ruling

    甲: the sys_audit_log rows written before #21174's fix stay as they are. ⛔ No one-time migration rewrites them. Closed not_planned: the migration is not done.

    Governing text.

    Why it holds.

    四棱(本裁决新记录)

    Execution


    Generated by Claude Code

  3. objectstack-fleet commented on Oct 2, 2026

    @objectstack-fleet
    ContributorAuthor

    Claim: PM loop round 1 (ruling execution on a closed card) · 2026-10-02T02:26Z
    Session: session_01DiCSbmJrkzNhuEAier4VoJ
    Account: os-bill (the seat's linked user)
    Branch: claude/issue-21198-changeset-note
    Worktree: objectstack-issue-21198
    Domain: domain:services
    Seat: domain:services#2 (seat post #21118)
    File surface: .changeset/21174-admin-audit-metadata.md only. One sentence is added, saying that rows written before this release keep their metadata, as ruling 甲 decides (5942375063, maintainer 「同意264」). Nothing else. Stop on breach; explain in the report.
    Container & model: S, mode:subagent, model: sonnet (one sentence in a pending changeset; no code).
    Clause-②: no
    Thread-read: 5942375063
    Serial constraints cleared, read in this act against origin/main at 748b24072: the changeset is still pending on main (not consumed by a release), and no open PR touches it.

    The foreign-changeset gate (#17712), declared before the build. This PR edits a pending changeset it did not add, so Check Changeset goes red on the PR by design. Ruling 5942375063 is the maintainer's confirmation of that edit ("This record is the maintainer's word for that edit of a pending changeset"). The by-design-red exception needs three conditions, all checked at landing: (1) the gate's own source says the red is by design on a pushed branch (.github/workflows/pr-automation.yml:728: "The red is the point … 'Check Changeset' is not one of the required contexts"); (2) the check does not run on merge_group; (3) a PR comment names the gate and the cause. If the changeset has shipped by the time this lands, the ruling record itself is the note and this PR closes unmerged.
    The card stays closed not_planned (the migration is not done). The PR body reads Refs #21198, never a closing keyword.


    Generated by Claude Code · https://claude.ai/code/session_01DiCSbmJrkzNhuEAier4VoJ

  4. objectstack-fleet commented on Oct 2, 2026

    @objectstack-fleet
    ContributorAuthor

    os-dev-report

    {
      "issue": 21198,
      "status": "done",
      "branch": "claude/issue-21198-changeset-note",
      "pr": "https://github.com/objectstack-ai/objectstack/pull/21300",
      "session": "session_01DiCSbmJrkzNhuEAier4VoJ",
      "premise_still_valid": true,
      "summary": "Ruling 甲 execution note, no code. Draft PR #21300 appends ONE sentence to the last paragraph of .changeset/21174-admin-audit-metadata.md, right after 'Rows written before this release are stored data and are not rewritten.': 'They keep the values their `metadata` already holds: the ledger is append-only (ADR-0052), so they stay as written by decision (#21198).' (the PM's suggested wording, unchanged; 1 file, +1/-1; no other edit). Premise held: the changeset is still on origin/main at 4e6dc2338 (so no release consumed it), plugin-auth CHANGELOG.md has no 21174 hit, PR #21195 merged as 55012df30, and none of the 16 open PRs (Version Packages #20639 included) lists the file. `Check Changeset` is red by design (#17712): locally `node scripts/check-empty-changeset.mjs --base origin/main` exits 1 with 'This PR changes a changeset it did not add'; it is not a required context (scripts/check-required-contexts.mjs REQUIRED_CONTEXTS, line 368, pins seven: Lint & Repo Gates, TypeScript Type Check, Test Core, Dogfood Regression Gate, Build Core, Temporal Conformance (live PG + MySQL), Governed Surface Queue Guard; AGENTS.md:518-522 lists the same seven) and does not run on merge_group (.github/workflows/pr-automation.yml:41-43 triggers on pull_request only, zero merge_group occurrences in the file; the job's own text at :728-730 says 'The red is the point ... not one of the required contexts'). No label and no changeset of this PR's own was added (skip-changeset is refused for this class, ruling D on #18375). PR #21300 is draft, assignee os-bill, no labels; body stored byte-identical (4176 bytes, diff against the sent file empty), first lines 'Refs #21198' and 'Clause-②: no', no closing keyword; the single PR comment (5944572645) names the gate, the cause and the confirmation (ruling 5942375063). CI on the PR had no check-runs yet at my one read (not polled); convergence is the PM's. Two deviations: (1) the commit trailer pair is model-free (Claude-Session + Co-authored-by: Claude) per os-dev.md, not the harness reminder's model-named Co-Authored-By, because the pre-push hook refuses a model identifier; (2) the PR body footer is the dispatch order's session-URL form, not the harness reminder's alternative form. One observation worth the PM's eyes: ADR-0052's own status line (docs/adr/0052-audit-is-not-the-activity-feed.md:3) reads 'Proposed (2026-06-16) - partially implemented', while ruling 5942375063 calls it 'accepted' and leans on Prime Directive #13 for it; the sentence I added cites the ADR only for the property it declares (append-only, :36 and :80; the code agrees: packages/plugins/plugin-audit/src/objects/sys-audit-log.object.ts:22 managedBy 'append-only'), not for its status, so it is true either way, and the ruling stands on the maintainer's word 「同意264」 regardless.",
      "tests": "No code, no build, no test run (os-verify-lock not used). Gates derived at the final head 98cd8b924 (git rev-parse --short HEAD) with `node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack --commands` (no paths; 1 path, +1/-1, 98cd8b924 vs merge base 4e6dc2338): 19 commands, each run with output redirected before the exit code was read. exit 0: check-adr-0087-registration.mjs --base origin/main ('this PR adds no declared-breaking changeset'); check-adr-0087-registration.mjs --self-test; check-changeset-no-major.mjs --base origin/main ('This diff introduces no `major` bump.'); check-changeset-no-major.mjs --self-test; check-closing-keyword-parity.mjs and its --self-test; check-comment-mask-corpus.mjs; check-empty-changeset.mjs --self-test; scripts/pm/release-rehearsal-clone.mjs --self-test; pnpm check:changeset-gate-self-tests; check:driver-memory-census; check:gitlink-declared; check:nul-bytes ('OK (scanned 9939 text file(s) ... no raw ASCII control bytes)'); check:objectui-changeset; check:pm-changeset-deadline-census; check:published-files; check:refd-timer-probe; check:watch-hint-literal. exit 1 (the by-design red, the only red): node scripts/check-empty-changeset.mjs --base origin/main, printing 'This PR changes a changeset it did not add: .changeset/21174-admin-audit-metadata.md present on the merge base and CHANGED by this PR'. Reconciliation (`--ran`, exit codes recorded as 'cmd :: exit N'): 'Run reconciliation - 19 derived, 19 run, 0 NOT-MEASURED, 0 UNRUN.' Outside the derivation, also run: node scripts/check-changeset-fixed.mjs exit 0 (roster under .changeset, flagged by the derivation) and pnpm check:required-contexts exit 0 ('7 required context(s) pinned'). Byte hygiene: control-byte scan over the changeset, the PR body and the comment texts empty. NOT MEASURED: repo-wide lint/typecheck lanes and the 59 artifact-roster families (CI-owned; diff touches no TypeScript); CI on PR #21300 (no check-runs existed on 98cd8b924 at my single read, no polling; convergence is the PM's). Shallow checkout (git rev-parse --is-shallow-repository true): no ancestry or history claim is made; 'not consumed by a release' rests on the file's presence on origin/main plus the absent CHANGELOG hit, not on an is-ancestor read. Hygiene: no managed block appeared in AGENTS.md (git status clean at the end); worktree node_modules removed and the worktree removed without --force.",
      "mcp_calls": "0 - no MCP calls of any kind; all reads were gh api GETs and local commands",
      "api_writes": "4 REST writes, all through the scripts/pm fleet-write relay as objectstack-fleet[bot] (each is one repository_dispatch to objectstack-ai/objectstack, executed by the relay run, each read back): (1) pr_create, POST /repos/objectstack-ai/objectstack/pulls (draft), request fw-20261002T023613Z-03f35e, run 36956395960, read-back 4176 bytes sent / 4176 stored identical, PR #21300; (2) label-write.mjs --issue 21300 --assign os-bill, POST /repos/objectstack-ai/objectstack/issues/21300/assignees, run 36956437364, read-back matches (assignee os-bill, 0 labels); (3) the one PR comment, POST /repos/objectstack-ai/objectstack/issues/21300/comments, run 36956486696, comment 5944572645, 1141 bytes sent / stored identical; (4) this os-dev-report comment, POST /repos/objectstack-ai/objectstack/issues/21198/comments. Not REST: two git pushes of claude/issue-21198-changeset-note (the empty-branch probe at 4e6dc2338, then 98cd8b924). No second Claim comment, no PATCH, no label write beyond the assignee, no write to the card's assignee. Reads (not writes): gh api GETs of issue 21198 and its comments, the open-PR list and per-PR file lists, PR 21195, PR 21300 and its comments, and one check-runs listing.",
      "open_questions": [],
      "out_of_scope_findings": [
        "carrier: 承接者:无 · noted, not filed (an observation, not a class a/b/c) · ADR-0052's status line (docs/adr/0052-audit-is-not-the-activity-feed.md:3) reads 'Proposed (2026-06-16) - partially implemented' while ruling 5942375063 cites it as 'accepted' and applies Prime Directive #13 ('an accepted ADR binds') to it; the ruling's outcome does not depend on it (maintainer word 「同意264」, and the append-only property is also declared in code at sys-audit-log.object.ts:22), but a later reader following the ruling's chain will hit the mismatch. docs/adr/** is a governed surface, so no edit was made. Dedupe words: ADR-0052 status Proposed accepted audit ledger append-only"
      ]
    }

    Generated by Claude Code

  5. objectstack-fleet commented on Oct 2, 2026

    @objectstack-fleet
    ContributorAuthor

    ACCEPT (seat review; lands under the by-design-red exception) · PR #21300 @ 98cd8b924 · domain:services seat 2 (#21118) · session_01DiCSbmJrkzNhuEAier4VoJ · 2026-10-02T02:42Z

    Basis: the dev report 5944586903, the execution claim 5944467576, ruling 甲 5942375063 (maintainer 「同意264」), and the diff.

    Noted for the director's ledger (no card): ruling 5942375063 cites ADR-0052 as "accepted" and applies Prime Directive #13 to it. The ADR's own status line (:3) reads "Proposed (2026-06-16) - partially implemented". The ruling's outcome does not depend on that status: it stands on the maintainer's 「同意264」, and the append-only property is declared in code too. A later reader following the ruling's chain will still meet the mismatch. docs/adr/** is governed, so nothing is edited here.

    Landing: once every check except Check Changeset is green on this head.


    Generated by Claude Code · https://claude.ai/code/session_01DiCSbmJrkzNhuEAier4VoJ

  6. objectstack-fleet commented on Oct 2, 2026

    @objectstack-fleet
    ContributorAuthor

    Execution record: the note is this ruling record (the changeset shipped first) · domain:services seat 2 (#21118) · session_01DiCSbmJrkzNhuEAier4VoJ · 2026-10-02T02:48Z


    Generated by Claude Code · https://claude.ai/code/session_01DiCSbmJrkzNhuEAier4VoJ

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions