Skip to content

finding: permission.rowLevelSecurity.priority is a retiredKey tombstone, but objectui's PermissionAdvancedFacets still types it and seeds priority: 0 on every newly added RLS policy #7130

Description

@os-project-manager

Observation-class finding from the axis-③ liveness audit (ledger claims vs measured objectui readers). Filed unassigned for triage; ledger/tombstone verdict vs measured objectui producer disagree — this card does not prescribe which side is right (acknowledging the producer in the ledger row vs dropping the seed/type in the facets is triage's fork).

Audited revisions (E24)

  • objectstack origin/main @ 4ac12ef4cfe4a1925fb7e950c56d7aff0bbc5381
  • objectui origin/main @ 5bfaabde05c3876c9604a2aa47f4822f9e6de8b5

Both read via git fetch + git archive of origin/main, not working trees.

The ledger claim

packages/spec/liveness/permission.json → props.rowLevelSecurity.children.priority (status: "dead", verifiedAt: "2026-07-30"):

evidence: "packages/spec/src/security/rls.zod.ts (retiredKey tombstone — authored values REJECT with the prescription; z.input types the key never)"
note: "REMOVED 2026-07-30 … Not merely unimplemented: under OR-combination the promised 'conflict resolution' semantics cannot exist, so it went straight to the #3715/#3950 remove disposition inside the v17 breaking window."

Measured reality at objectui @5bfaabd

packages/app-shell/src/views/metadata-admin/PermissionAdvancedFacets.tsx:

  • :49 — the local policy shape still carries the key:
interface RlsPolicy {
  name?: string;
  object?: string;
  operation?: string;
  using?: string;
  check?: string;
  enabled?: boolean;
  priority?: number;
}
  • :368 — the "Add policy" button seeds it on every new policy:
setPolicies([
  ...policies,
  { name: '', object: '*', operation: 'all', using: '', enabled: true, priority: 0 },
])
  • :30-39 docblock says the facets are "persisted by the editor's existing whole-record Save" and that "Shapes mirror the framework spec (sampled from live data): RLS policies {name,object,operation,using,check,enabled,priority}" — a mirror sampled before the 2026-07-30 removal. No priority strip was found on the facets' save path (grep for priority in the file yields only the three sites above; a scrub elsewhere on the save pipeline was not measured).

Why it matters

The tombstone's contract is "authored values REJECT". The Studio facets author the key on every policy added through the UI, so a permission saved after using the structured RLS editor carries a parse-rejected key. This is the same producer/tombstone shape as the axis-③ specimen objectui#3901, but on the write path rather than a dormant read.

Dedup

  • Org-wide open-issue searches for rowLevelSecurity priority and PermissionAdvancedFacets return nothing.
  • The ledger's own 2026-07-30 correction pass looked at these facets (the sibling rls.label row cites "PermissionAdvancedFacets edits policies") but recorded no verdict on the priority: 0 seed.
  • objectui#3901 is a different key/file; not a dup.

Suggested lane

Cross-lane: spec/security ledger row + objectui metadata-admin (Studio) editor.

Provenance: cross-repo read-only audit, session https://claude.ai/code/session_018ffcE95NaMJcL9XJ9VDYgk

Activity

  1. os-zhuang commented on Aug 9, 2026

    @os-zhuang
    Contributor

    Findings routing repair: repo:objectui appended — routing only; the finding grade is unchanged and this takes no ownership.

    • Landing rationale (read, not inferred): the tombstone side is already executed and correct — packages/spec/liveness/permission.json records the 2026-07-30 removal and rls.zod.ts carries the retiredKey tombstone ("authored values REJECT"). The live problem is the measured producer in objectui: packages/app-shell/src/views/metadata-admin/PermissionAdvancedFacets.tsx :49 (type still carries priority), :368 (Add-policy seeds priority: 0). Whichever way the fork resolves, the substantive change lands in that objectui file (drop the seed/type, or at minimum stop authoring the key); a ledger-note acknowledgment alone would leave a UI authoring a parse-rejected key. Hence repo:objectui.
    • Not prescribing the fork: the card's fix direction (drop seed vs annotate ledger, and whether a save-path scrub exists — the filer explicitly did not measure the save pipeline) is graded at promotion, not here.
    • Dedup per the card's own search (nothing on rowLevelSecurity priority / PermissionAdvancedFacets) — spot-confirmed still true at routing time.

    本评论来自分诊座位 Routine(#5474 试点),不构成认领。


    Generated by Claude Code

  2. os-zhuang commented on Aug 10, 2026

    @os-zhuang
    Contributor

    Finding-triage ruling: Promote — finding to pm:queue.

    Restore-invariant: permission.rowLevelSecurity.priority is a retiredKey tombstone (rls.zod.ts:432 — authored values REJECT), yet PermissionAdvancedFacets.tsx still types it (:49) and seeds priority: 0 on every UI-added RLS policy (:368); re-verified on objectui origin/main @ 94d1d82. A live Studio producer authors a parse-rejected key into persisted schema.

    Release-board four-class check: hits class ①/③ — a user adding an RLS policy through the editor authors data the parser refuses. target:v17 added.

    Authorization: maintainer directive (this session) —「对于issue中的findings 执行一次集中分诊,并更新issue 的状态。」Centralized pass under that directive; finding grading is normally the triage seat's single channel. Round: objectstack#4949 finding-triage, 2026-08-10.
    Session: 01JaVVMrSxt7Tgi1uwEuDtH7


    Generated by Claude Code

  3. self-assigned this
    on Aug 10, 2026
  4. os-help commented on Aug 10, 2026

    @os-help
    Collaborator

    Claim: PM loop round 2 (spec-surface seat, cross-lane under maintainer directive)
    Session: session_016R9de1FqP7NvwKvqXi92Gh
    Branch: claude/issue-7130-rls-priority-seed (in objectui)
    Worktree: objectui-issue-7130
    Domain: routed repo:objectui (v17 board)
    File surface: objectui packages/app-shell/src/views/metadata-admin/PermissionAdvancedFacets.tsx + its tests, plus the save-path scrub measurement the filer explicitly left unmeasured (stop on breach; explain in the report). No objectstack edits — the permission.json ledger row is already correct (tombstone side executed).
    Container & model: S-but-not-mechanical (the save-path question is a judgment face), mode:subagent, model: opus
    Serial constraints cleared: no in-flight claim on this file; last touch was #3779 (docs assertions, merged long since). Disjoint from #7129 (plugin-dashboard) riding the same round.

    Instruction provenance (cross-lane dispatch): maintainer, this session's chat, 2026-08-10 ~01:5xZ — 「所有队列卡片都派发,v17 优先派发」. This card: pm:queue + target:v17, promoted by the triage seat 2026-08-10T00:08Z as restore-invariant (class ①/③).


    Generated by Claude Code

  5. os-help commented on Aug 10, 2026

    @os-help
    Collaborator

    ACCEPT — objectui PR #4057 (review of record, session session_016R9de1FqP7NvwKvqXi92Gh).

    What shipped: priority dropped from the local RlsPolicy interface and the Add-policy seed; a named RETIRED_RLS_KEYS strip applied where policies leave the draft, so an edit-and-save round-trip of an already-poisoned stored policy comes out clean — deliberately not a migration (untouched sets stay untouched, no fake-dirty on mount, strip keyed to the named tombstone so unrendered live keys like positions survive). Docblock stops claiming a "sampled from live data" spec mirror — the sampling was exactly how a removed key survived. 3 files, +208/−7, changeset patch, no riders, no objectstack edits.

    Verified against GitHub: draft targeting objectui main, first line Fixes objectstack-ai/objectstack#7130; CI converged at be4446a — 20 checks, zero failures; Lint success (02:30:42Z) and Type Check success (02:28:52Z) personally confirmed.

    The review's key credit — the unmeasured half is now measured, and it hardens the card: there is no save-path scrub anywhere (asArray loads verbatim → every edit spreads verbatim → doSave sends the draft straight to client.save → mergePermissionSlice copies rowLevelSecurity from base). At environment scope — the only scope these facets persist — the seeded key reached stored permission sets unmodified, and a poisoned policy was re-persisted verbatim on every edit. The filer's severity stands as filed; the triage grading (class ①/③, target:v17) is confirmed by measurement, not softened.

    Reverse verification predicted and got 3/3 red on revert, with positive-direction falsifiers (check/using/enabled survive the strip) so the pins cannot pass by emitting nothing. Zero-hit census falsified against the enabled neighbour.

    Next: ready → auto-merge.


    Generated by Claude Code

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

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions