Skip to content

A sharing rule on an object without record sharing saves and silently does nothing #30621

Closed

Description

@objectstack-fleet

domain:server#6 · os-bill · session_01Utp6CXCS98uhsFQYk64epE

Found by the #30209 card thread while measuring row 5 (os-dev-report 6665615192 on PR #30620, out_of_scope_findings, class (c) trap).

What

An administrator can save a sharing rule (sys_sharing_rule) on an object that is not under record-sharing enforcement (measured: sys_session, sys_account, sys_api_key). The save answers 201. The reconcile then logs WARN SHARING_NOT_ENABLED and writes no sys_record_share, so the rule's recipients see nothing more than before. Nothing tells the administrator: the rule sits in Setup looking active and never applies.

Measured: no widening. The rule grants nothing, so this is a misleading-configuration trap, not an access problem.

Expected

The administrator learns at save time that the object does not use record sharing. Either the save door refuses a rule whose object is not under enforcement, with a sentence naming the object and how to enable sharing for it, or the rule is saved and carries a visible "not in effect" state. Refusal is the simpler contract; pick per the existing sharing-rule validation in packages/plugins/plugin-sharing.

Related: #30209 row 5 (the rule's object picker lists every object) is a separate decision on the same surface: option C there is this card's refusal.

Surface

packages/plugins/plugin-sharing (the sys_sharing_rule save path / validation) and its tests; changeset per the outcome (a save refusal is a narrowing).

Activity

  1. added
    bugSomething isn't working
    domain:serverDomain lane — seat card indexed by label:pm:seat
    pm:queueReady for the PM dispatch loop
    on Nov 5, 2026
  2. objectstack-fleet commented on Nov 6, 2026

    @objectstack-fleet
    ContributorAuthor

    triage#1 · os-zhuang · session_01AavokzJ5DndAwitDXvKy4U

    Path: none

    Triage: audit · p3 kept · domain:server · re-queued · 2026-11-06T12:47Z

    ⛔ Not a claim.

    • A sharing rule on an object without record sharing saves and does nothing. It should be refused at save. It over-grants nothing, so p3.
    • Triage re-queued it at 12:28Z: the card had a grade and a lane but no pm:* state, so no seat could see it. That was a triage sweep miss, fixed this round.

    Generated by Claude Code

  3. objectstack-fleet commented on Nov 6, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:server#4 · os-elon-musk · session_016WV4czvZykUqhYxYXSSDt4

    Claim: PM loop round 1 · 2026-11-06T12:55Z
    Session: session_016WV4czvZykUqhYxYXSSDt4
    Account: os-elon-musk (the seat's linked user as GET /user answers it; the card's assignee)
    Branch: the card thread's designated claude/project-thread-* branch, re-posted in a whole claim once the thread reports it
    Worktree: objectstack-issue-30621
    Domain: domain:server
    Seat: domain:server#4
    File surface: the sys_sharing_rule save path and its validation in packages/plugins/plugin-sharing/**; their tests; the docs sentences this makes false; one root .changeset/ file. ⛔ packages/spec/** (a new error code needs a ledger row: stop, and the seat files the domain:spec sub-card, unless the code already exists), ⛔ ui/** (stop on breach; explain in the report)
    Container & model: S, mode:thread, model: default, effort: medium
    Clause-②: no (narrowing) (provisional: refusing a save that answers 201 today narrows the save door's accept set)
    Metadata-protocol: none
    Responsibility: n/a — misleading-configuration trap found by the #30209 card thread
    Thread-read: 6685173622
    Premise: card body and triage 6685173622 (p3 kept). The save door refuses a sharing rule whose object is not under record-sharing enforcement, with a sentence that names the object and how to enable sharing for it. This is the simpler contract the card prefers. Existing rules on such objects are listed in the report, not migrated.
    Serial constraints cleared: the dev re-reads open PRs touching packages/plugins/plugin-sharing at branch start

    Contract review owed (the narrowing) before the queue.

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

    @objectstack-fleet
    ContributorAuthor

    domain:server#4 · os-elon-musk · session_016WV4czvZykUqhYxYXSSDt4

    Claim: PM loop round 1 (whole claim re-posted with the branch) · 2026-11-06T13:02Z
    Session: session_016WV4czvZykUqhYxYXSSDt4
    Account: os-elon-musk (the seat's linked user as GET /user answers it; the card's assignee)
    Branch: claude/project-thread-lpcxlh
    Dev session: session_016WV4cyFB75QwwCDu3S5GNZ (card thread; base 33043bd8)
    Worktree: objectstack-issue-30621
    Domain: domain:server
    Seat: domain:server#4
    File surface: the sys_sharing_rule save path and its validation in packages/plugins/plugin-sharing/**; their tests; the docs sentences this makes false; one root .changeset/ file. ⛔ packages/spec/** (the refusal reuses the existing SHARING_NOT_ENABLED 422, already in the plugin-sharing ledger row; a new code would need a ledger row: stop, and the seat files the domain:spec sub-card), ⛔ ui/** (stop on breach; explain in the report)
    Container & model: S, mode:thread, model: default, effort: medium
    Clause-②: no (narrowing) (provisional: refusing a save that answers 201 today narrows the save door's accept set)
    Metadata-protocol: none
    Responsibility: n/a — misleading-configuration trap found by the #30209 card thread
    Thread-read: 6685173622
    Premise: card body and triage 6685173622 (p3 kept). The save door refuses a sharing rule whose object is not under record-sharing enforcement, with a sentence that names the object and how to enable sharing for it. This is the simpler contract the card prefers. Existing rules on such objects are listed in the report, not migrated. The door reuses SharingService's own inert-grant verdict, the one the reconcile raises SHARING_NOT_ENABLED on.
    Serial constraints cleared: the dev re-reads open PRs touching packages/plugins/plugin-sharing at branch start

    Contract review owed (the narrowing) before the queue.

  6. objectstack-fleet commented on Nov 6, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:server#4 · os-elon-musk · session_016WV4cyFB75QwwCDu3S5GNZ
    os-dev-report

    {
     "issue": 30621,
     "status": "done",
     "branch": "claude/project-thread-lpcxlh",
     "pr": "https://github.com/objectstack-ai/objectstack/pull/30953",
     "session": "session_016WV4cyFB75QwwCDu3S5GNZ",
     "premise_still_valid": true,
     "summary": "Both sharing-rule save doors now refuse a rule whose object is not under record-sharing enforcement with SHARING_NOT_ENABLED 422 and save nothing: the /data door through a new sys_sharing_rule hook guard (bindRuleObjectEnforcementGuard, bound beside the criteria guard; an update is checked only when it moves the rule to another object) and SharingRuleService.defineRule for non-system callers. The verdict is the reconcile's own: SharingService.sharingRuleObjectRefusal reads the same objectInertReason that assertNotInertGrant now calls, plus a per-arm remedy sentence naming the object. Existing code SHARING_NOT_ENABLED (already in the plugin-sharing ledger row), no spec change; public objects with an owner column stay admitted (#25549 external recipients); system writes pass as with the declared-name guard.",
     "tests": "head 6a24dc2567 (code unchanged since 1390d368). New sharing-rule-object-enforcement.test.ts (real ObjectQL + SqlDriver): before fix 8 failed (8), after 8 passed (8). Ablation via scripts/ablation-replace.mjs on sharingRuleObjectRefusal (if (!reason) -> if (reason || !reason)): 4 failed | 4 passed (the 4 refusal pins red, 4 controls green); restore blob == HEAD 2afbcaad0cda, git diff HEAD empty; suite imports src/ relatively, no dist on the path. plugin-sharing pnpm test: Test Files 68 passed (68), Tests 1444 passed (1444); pnpm typecheck incl. check:test-typecheck exit 0 (lock VERDICT command-exit 0). Scratch probe (not committed) of rest mapDataError/classifiedRefusalAnswer: 422 SHARING_NOT_ENABLED with the sentence on both doors.",
     "gates": "dispatch-gates --commands: 96 families over 10 paths; all 96 ran on 6a24dc2567 with exit 0; --ran: '96 derived famil(ies) accounted for — 96 run, 0 NOT-MEASURED'. First pass on 1390d368: 95 green, check:system-context-census red ([read-without-a-row] bindRuleObjectEnforcementGuard, defineRule), fixed in 6a24dc2567 by keying census row 40 and --write. Prereqs: unshallow fetch + whole-tree turbo build 119/119. CI check-runs: in_progress at report time (seat reads them).",
     "dogfood_battery": "1390d368 (6a24dc2567 adds only a docs census row) · os-verify-lock: VERDICT command-exit 0 · Test Files 425 passed | 3 skipped (428) · Tests 3543 passed | 41 skipped (3584) · no failures",
     "mcp_calls": "0",
     "api_writes": "2 — fleet-write pr_create (POST pulls, #30953) and this os-dev-report comment (POST issues/30621/comments); git push x2 is not REST",
     "open_questions": [],
     "security_findings": "none",
     "out_of_scope_findings": [
      "observation, not filed · lint validate-sharing-rule-enforceability anchorFindings reports a declared rule on a public-model object as inert, while the runtime admits a public object with an owner column for external recipients (#25549); read-only inference, no reach measured · carrier: none",
      "observation, not filed · #30209 row 5 (the rule form's object picker lists every object) remains; this PR is that card's option C on the save side only · carrier: #30209"
     ]
    }

    Generated by Claude Code

  7. objectstack-fleet commented on Nov 6, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:server#4 · os-elon-musk · session_016WV4czvZykUqhYxYXSSDt4

    Landing record · 2026-11-06T16:48Z · PR #30953 merged through the queue as ee874b1f5e. Before that: the seat's ACCEPT 6688136157 on head dc804fbb, contract review PASS 6687390627 on 6a24dc25, delta review PASS 6688105703 on dc804fbb, and the maintainer's BREAKING word 6688116131. A sharing rule on an object without record-sharing enforcement is now refused at both save doors with 422 SHARING_NOT_ENABLED. Stored rules are not migrated. Card closed completed by Fixes; pm:dispatched removed in this stroke. #30209 row 5 (the object picker) remains with its card.

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:p3

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions