Skip to content

Assigned work (#30205): the count and the handover skip the platform's injected owner_id, so a banned user owns nothing on most objects #30646

Closed

Description

@objectstack-fleet

domain:ui#4 · os-sales · session_01L6bhgVfPeFZkN1FP93imKU

立卡门类别:① 已复现缺陷(真栈读数 + 源码对读)。Reader: domain:server(packages/core/src/security/user-assigned-work.ts,PR #30546 的服务器半)。由 #30205 ui 半的卡线程在实测封禁对话框时发现。

维护者速读

#30205 的服务器半(PR #30546,19:41Z 合并)新增了「这个人手上有多少记录」和「批量转交」两个接口。可它挑字段时跳过了所有 system: true 的字段,而平台给每个业务对象注入的 owner_id(记录负责人)正好是 system: true。结果:只有作者自己声明了 owner_id 的对象会被计入,绝大多数对象上「他拥有多少条」恒为 0,转交也不会移交负责人。这和该文件头写的「That includes the platform's owner_id」相反。

已实测

  1. 卡线程在 showcase 真栈(main 14c67d44)把 3 条 showcase_project 的 owner_id 改成用户 Lee,GET /api/v1/security/users/<Lee>/assigned-work 的 objects 只有 showcase_field_zoo 的 f_user、f_users,没有 showcase_project。GET /meta/object/showcase_project 里注入的 owner_id 是 lookup → sys_user,system: true。作者自己声明 owner_id 的对象(如 showcase_announcement)照常计入。
  2. 本席对读源码(origin/main 14c67d44):
    • packages/core/src/security/user-assigned-work.ts:102:if (d.readonly === true || d.system === true) continue;
    • packages/spec/src/data/injected-system-column-provenance.ts:131 OWNER_FIELD_DEF:readonly: false、system: true,注释写明「ownership is transferable … NOT readonly」。
    • 计数(:164)和转交(:279)读的是同一份 userAssignedWorkFields,所以两处都漏。
    • user-assigned-work.test.ts 的 fixture 里 owner_id 没带 system: true(:17、:24),所以现有测试没看出来。

方向

排除审计字段要靠 readonly(created_by / updated_by 是 readonly),不靠 system。改成只跳过 readonly: true,或在跳过 system 时为注入的 owner_id 留例外(以 OWNER_FIELD_DEF / 注入来源为准,不按字段名猜)。测试 fixture 改用真实的注入定义,并加一例:注入 owner_id 被计数、被转交,created_by 仍不计。

完成标准

  • 注入了 owner_id 的业务对象,在计数和转交里都出现;created_by、updated_by 仍不出现。
  • sys_*、managedBy 对象、未落库的注入列照旧排除。
  • 有一例用 OWNER_FIELD_DEF 原样定义的 pin,删掉修复会转红。

关联

Activity

  1. objectstack-fleet commented on Nov 5, 2026

    @objectstack-fleet
    ContributorAuthor

    triage#1 · os-zhuang · session_01AavokzJ5DndAwitDXvKy4U

    Path: none

    Triage: audit · p2 · domain:server · 2026-11-05T20:12Z

    ⛔ Not a claim.


    Generated by Claude Code

  2. added
    domain:serverDomain lane — seat card indexed by label:pm:seat
    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 5, 2026
  3. objectstack-fleet commented on Nov 5, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:server#1 · os-elon-musk · session_016WV4cytLmJxfAmgPVjUbbW

    Claim: PM loop round 1 · 2026-11-05T21:32Z
    Session: session_016WV4cytLmJxfAmgPVjUbbW
    Account: os-elon-musk (the seat's linked user as GET /user answers it; the card's assignee)
    Branch: claude/issue-30646-owner-id-assigned-work
    Worktree: objectstack-issue-30646
    Domain: domain:server
    Seat: domain:server#1
    File surface: packages/core/src/security/user-assigned-work.ts, user-assigned-work.test.ts (fixture from the real injected OWNER_FIELD_DEF), one root .changeset/ file (stop on breach; explain in the report)
    Container & model: S, mode:subagent, model: default (dispatch-gates --tier: no path-derived mandate; floor sonnet · default opus · ceiling fable), effort: medium
    Clause-②: no
    Metadata-protocol: none
    Responsibility: the assigned-work field picker in packages/core/src/security/user-assigned-work.ts:102 (skips every system: true field, the injected owner_id included) | none | every administrator banning a user: owned records are neither counted nor handed over (reproduced live on the card)
    Thread-read: 6668173130
    Premise: holds per the card at origin/main 14c67d44; the dev re-reads :102 on origin/main first
    Serial constraints cleared: none: no open PR touches user-assigned-work.ts (34 open PRs read at claim time); PR #30546 (the #30205 server half) is merged

  4. objectstack-fleet commented on Nov 5, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:server#1 · os-elon-musk · session_016WV4cytLmJxfAmgPVjUbbW
    os-dev-report

    {
      "issue": 30646,
      "status": "done",
      "branch": "claude/issue-30646-owner-id-assigned-work",
      "pr": "https://github.com/objectstack-ai/objectstack/pull/30677",
      "session": "session_016WV4cytLmJxfAmgPVjUbbW",
      "premise_still_valid": true,
      "summary": "Premise held on origin/main f4d568ba: user-assigned-work.ts:102 skipped `readonly === true || system === true`, and OWNER_FIELD_DEF is system: true, readonly: false, so the injected owner_id was neither counted nor handed over. The picker now excludes by readonly only (audit lookups are readonly as injected and are forced readonly when declared, via applyAuditFieldGovernance); sys_*, managedBy and unprovisioned injected columns stay excluded. The test fixture now uses the real OWNER_FIELD_DEF / AUDIT_FIELD_DEFS, with one new pin. Card assignee not touched; PR carries no assignees.",
      "tests": "head 90919afc. `pnpm --filter @objectstack/core exec vitest run --project local --maxWorkers=2 src/security/user-assigned-work.test.ts`: Tests 12 passed (12), lock VERDICT command-exit 0. `pnpm --filter @objectstack/core test`: Test Files 136 passed (136), Tests 3087 passed (3087), VERDICT command-exit 0. `pnpm --filter @objectstack/core typecheck`: VERDICT command-exit 0 (check:test-typecheck OK). Ablation via scripts/ablation-replace.mjs on the committed fix (subject imported by relative path from src, no dist leg): leg 1 restore the `system === true` skip -> anchor 1->0, blob 641afd9e->25d76e52, `Tests 9 failed | 3 passed (12)`, new pin `expected [] to deeply equal [ { object: 'deal', ... } ]`; restored, blob == HEAD 641afd9e, git diff HEAD empty. Leg 2 (control) delete the readonly skip -> `Tests 5 failed | 7 passed (12)` (created_by / updated_by picked); restored, blob == HEAD, git diff HEAD empty.",
      "gates": "`node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack` at 90919afc: 60 commands; each run with exit code captured before any pipe. 57 exit 0 on first run; `node scripts/check-plugin-teardown-shape.mjs --self-test` exit 3 (shallow clone, pinned fixture commit 621a4876 missing) -> fetched that commit, rerun exit 0; `pnpm check:lean-entry-closure` exit 3 (objectql dist missing) -> built @objectstack/objectql, rerun exit 0; `pnpm check:dual-build-cjs-loads` exit 3 PREREQUISITE NOT MET (needs a full `pnpm build`) = NOT MEASURED, CI Lint & Repo Gates runs it. `--ran` reconciliation: exit 0, '60 derived famil(ies) accounted for, 59 run, 1 NOT-MEASURED (1 DERIVED from a recorded exit 3)', 0 UNRUN. `pnpm lint`: exit 0. CI check-runs: in_progress at report time (not awaited, per contract).",
      "dogfood_battery": "n/a: no `!` in the PR title and no (narrowing) arm",
      "line_budget": "45 changed lines (+36 / -9) across 3 files, under the 3000 human-merge threshold",
      "files_changed": [
        "packages/core/src/security/user-assigned-work.ts",
        "packages/core/src/security/user-assigned-work.test.ts",
        ".changeset/30646-assigned-work-injected-owner.md"
      ],
      "deviations": [
        "test:repo not run locally (diff touches no repo-project test); CI Test Core runs it",
        "No empty-branch probe push before the first edit: the branch was named in the claim and pushed once with the first commit",
        "Local subset narrowed: check:dual-build-cjs-loads NOT MEASURED (full build prerequisite); declared, CI runs it"
      ],
      "mcp_calls": "0: no MCP GitHub calls of any kind",
      "api_writes": "3: git push (not REST); relay pr_create via fleet-write dispatch (repository_dispatch, run 42118647373, PR #30677, draft, read-back identical 4465 bytes); this os-dev-report comment via post-stamped.mjs",
      "open_questions": [],
      "security_findings": "none",
      "out_of_scope_findings": []
    }
  5. objectstack-fleet commented on Nov 5, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:server#1 · os-elon-musk · session_016WV4cytLmJxfAmgPVjUbbW

    ACCEPT → PR #30677 comment 6671351229 · head 90919afc · ready + auto-merge set 2026-11-05T22:38Z

  6. objectstack-fleet commented on Nov 5, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:server#1 · os-elon-musk · session_016WV4cytLmJxfAmgPVjUbbW

    Landed · 2026-11-05T23:00Z · PR #30677 merged by the queue as badf24dffc (2026-11-05T23:00Z), so the card closed by Fixes. This seat strips pm:dispatched in the same act.

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

Metadata

Metadata

Assignees

Labels

bugSomething isn't workingdomain:serverDomain lane — seat card indexed by label:pm:seatpriority:p2Medium: important, M3

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions