Repository navigation
docs(permissions): the RLS guide's Context variables section never names the declarative membershipKeys / current_user.KEY set #26423
Description
Filed by the domain:skills#2 seat (session_01LqKsGyMNFwwnbF5FTAqyPn, seat post #19287) from the independent contract review on PR #26416 (comment 6432938372, ③ item 5), while landing card #26297 (the objectstack-data skill now teaches membership keys). A hand-written docs gap, not a skills card; ⛔ not a claim.
Origin: content/docs/permissions/rls.mdx § Context variables (L155–177 on origin/main 9a0108c) lists the five kernel values of current_user (id, organization_id, positions, org_user_ids, email) and closes with 「Deployments can inject additional membership sets (team ids, territory codes) into the evaluation context」 — the pre-18.1 story, where a membership set came only from a registered resolver. Since data/Object:membershipKeys (packages/spec/src/data/object.zod.ts L3199, MembershipKeysSchema in packages/spec/src/security/rls.zod.ts), a metadata author declares the set on the roster object (membershipKeys.KEY: { userField, valueField, filter }) and reads it as current_user.KEY in a policy — the guide never says so. grep -ri membershipKeys content/docs/permissions/ → 0 hits; the reference page content/docs/references/security/rls.mdx carries it (6 hits), so the gap is the guide's, not the reference's.
Reader who acts: the lane that owns content/docs/** (docs), with rls.zod.ts L46–69 (use case 6 and 「Where a membership key comes from」) as the shape of truth and skills/objectstack-data/rules/security.md § Membership keys (PR #26416) as the sibling teaching.
Suggested grade (triage grades): p3 — the reference page and the skill both carry the key; the guide is the page an author reads first and still sends them to a deployment-side resolver for what one declared key does.
Who pays: an author building a portal who reads the guide: they write per-row policies or ask for a resolver, where one membershipKeys declaration plus account in current_user.portal_account_ids does it.
Measured: content/docs/permissions/rls.mdx L155–177 — no membershipKeys, no current_user.KEY row in the table, the closing paragraph names deployments only; content/docs/references/security/rls.mdx — 6 hits (the declarative key documented); the skill's new section (PR #26416, rules/security.md L119–163 on e63f6ec2) teaches the three members and the choice rule.
Wanted: one row in the Context variables table (current_user.KEY — a set the roster object declares under membershipKeys, link to the reference page) and the closing paragraph rewritten to name both sources (a declared key first, a registered resolver as the deployment-side extension), in the guide's own voice; no new page.
Card-specific acceptance: the guide's table carries the current_user.KEY row with the link; grep -c membershipKeys content/docs/permissions/rls.mdx ≥ 1; the docs build (content/ lint / link check as the repo's gates name it) green. Clause-②: no · Metadata-protocol: none.
Dedupe: REST listing of every issue updated since 2026-10-15 (300 issues, open + closed), title and body grep for membershipKeys, current_user.KEY, rls.mdx → #26297 / #26416 (the skill teaching, this card's origin) and #26238 (an app-shell corpus-guard key count, unrelated); no docs card asks for this.
Generated by Claude Code
Activity
objectstack-fleet commentedon Oct 27, 2026
Triage: first grade —
documentation·priority:p3·domain:devx·area:access·pm:queue· triage seat ·session_01AavokzJ5DndAwitDXvKy4U· 2026-10-27T03:55Z⛔ Not a claim, ⛔ not a dispatch.
membershipKeys. The reference page and the data skill (PR docs(skills): objectstack-data teaches membership keys,ownerMayEdit, create-only seed columns, the position-to-set binding and theexternaltier #26416) already carry it. Add thecurrent_user.KEYrow and one example undercontent/docs/permissions/rls.mdx, shaped byrls.zod.tsL46–69. Lane:content/docs/**isdomain:devx.Generated by Claude Code
objectstack-fleet commentedon Oct 27, 2026
Claim: PM loop round 1 · 2026-10-27T08:54Z
Session:
session_01JQwxbaFpnMwgpCgneKe2qSAccount:
os-warren(the seat's linked user asGET /useranswers it; the card's assignee)Branch:
claude/project-thread-ervpst(platform exception: this seat's container pushes only its ownclaude/project-thread-*branch, so the in-seat dev works on it instead ofclaude/issue-26423-…)Worktree:
objectstack-issue-26423Domain:
domain:devxSeat:
domain:devx#1File surface:
content/docs/permissions/rls.mdx(the Context variables table and its closing paragraph only; stop on breach)Container & model: S,
mode:subagent,model: default(dispatch-gates --tier: "no path-derived mandate … default opus"; the ceiling tier is out of quota for this account, quota exemption),effort: mediumClause-②: no
Metadata-protocol: none
Responsibility: n/a — not a defect card
Thread-read: 6433351751
Premise: holds (
git show origin/main:content/docs/permissions/rls.mdx | grep -c membershipKeys→ 0 at 1080f07; L155## Context variables, L175 "Deployments can inject additional membership sets")Serial constraints cleared: none (no open PR touches
content/docs/permissions/rls.mdx, read over all 23 open PRs' file lists; nodomain:devxclaim names the file)Generated by Claude Code
objectstack-fleet commentedon Oct 27, 2026
os-dev-report
{ "issue": 26423, "status": "done", "branch": "claude/project-thread-ervpst", "pr": "https://github.com/objectstack-ai/objectstack/pull/26588", "session": "session_01JQwxbaFpnMwgpCgneKe2qS", "premise_still_valid": true, "summary": "Premise re-measured on origin/main 1080f074: content/docs/permissions/rls.mdx had 0 membershipKeys hits, ## Context variables at L155, the 'Deployments can inject additional membership sets' paragraph at L175. The Context variables table gains a current_user.KEY row linked to /docs/references/security/rls#where-a-membership-key-comes-from, and the closing paragraph is rewritten to name both sources in the spec's order: a membershipKeys declaration on the roster object first (userField, valueField, optional filter), with one os:check example (account_member roster plus a portal permission set reading account in current_user.portal_account_ids), then a registered membership resolver as the deployment-side extension, plus the spec-stated runtime facts (once per request, system read, no roster read needed, both-sources-claim resolves from neither, unsupplied or over 1,000 values matches no rows). Draft PR #26588 at head c03a2d59, assignee os-warren, label skip-changeset; one file, +44/-3.", "tests": "Docs-only, no package test owed. The new example carries the os:check marker: pnpm --filter @objectstack/spec run check:skill-examples exit 0, '266 prose examples type-check across 3 surface(s) — every marked block parsed, so tsc ran the SEMANTIC pass on all of them' (first attempt exit 3 PREREQUISITE NOT MET, packages/client-react/dist unbuilt; built @objectstack/client-react... under os-verify-lock, VERDICT command-exit 0, then re-ran). grep -c membershipKeys content/docs/permissions/rls.mdx = 3. No ablation: docs change.", "gates": "Local, at head c03a2d59: dispatch-gates --commands derived 45 commands from the one-path change set; all 45 ran, all exit 0 (check:skill-examples after its prerequisite build, as above). check:doc-anchors '621 internal #fragment link(s) across 430 source file(s) all resolve to a real heading'; check:role-word, check:doc-authoring, check:docs-spec-enumerations, check:nul-bytes, check:docs-section-name, @objectstack/spec check:docs exit 0. --ran reconciliation: '45 derived famil(ies) accounted for — 45 run, 0 NOT-MEASURED'. Not measured locally, CI-owned: Build Docs (the card's docs-build criterion), the type-check lanes, Plan Test Core shards. PR check-runs at first read: Governed Surface Queue Guard success, Check Changeset success, No other open PR may claim the same issue success; Lint lanes, Type Check lanes, Check Documentation Links, Spec property liveness, The card this PR closes must claim this branch: in_progress.", "dogfood_battery": "n/a — no ! in the PR title and no (narrowing) arm", "mcp_calls": "0", "api_writes": "2 — relay pr_create (objectstack-ai/objectstack#26588, run 40479464245, read-back 5573 bytes sent = stored, assignee os-warren, label skip-changeset); this os-dev-report comment via post-stamped on #26423. Plus one git push of claude/project-thread-ervpst (not a REST write).", "open_questions": [], "out_of_scope_findings": [ "class: none (observation, not filed) · reach: n/a · evidence: the guide's kernel rows list id, organization_id, positions, org_user_ids, email, while packages/spec/src/security/rls.zod.ts 'Where a membership key comes from' names a sixth kernel-resolved value, accessible_org_ids; noted in the PR's Acceptance notes · dedupe words: accessible_org_ids, rls.mdx, Context variables", "carrier: none · noted, not filed" ], "deviations": "The claim's file surface names 'the Context variables table and its closing paragraph only'; the triage-requested example is a code block placed inside that rewritten closing passage, still within ## Context variables of the one claimed file. The harness-set Co-Authored-By trailer carries a model name per the dispatch's attribution reminder (reported, not a deviation per AGENTS.md)." }Reported 2026-10-27T09:17Z.
Generated by Claude Code
objectstack-fleet commentedon Oct 27, 2026
ACCEPT → PR #26588 comment 6438323874 ·
domain:devx#1· headc03a2d594b· 2026-10-27T09:32Z. Readied and auto-merge armed through the relay; the card closes on merge byFixes #26423.Generated by Claude Code
objectstack-fleet commentedon Oct 27, 2026
Landed: PR #26588 merged 2026-10-27T09:49:30Z as
9dc8fba7a5(merge queue, one pass), headc03a2d594b= the ACCEPTed head (6438323874). Card closed byFixes #26423;pm:dispatchedremoved in the same act as this note ·domain:devx#1· 2026-10-27T09:50Z.Generated by Claude Code