Repository navigation
member_default's removed wildcard is still named as live fact in platform-objects, qa/dogfood and the permissions doc — the #6842 family, four packages further out #6964
Description
Found while implementing #6842 (PR #6958). Filed unassigned for the triage round to grade — most of it is observation-class prose drift, but Part 2 may not be, so it is deliberately left unlabeled rather than pre-graded as finding.
Context
#6842 framed the drift as "three separate pieces of prose went stale when #5491 (PR #6684) removed member_default's plain '*' wildcard grant" — the packages/spec JSDoc (fixed by #6696 / PR #6846) and two it() titles in plugin-security (fixed by PR #6958). Grepping the whole repo for member_default co-occurring with wildcard language shows the count was not three. At least six more live sites survive in three other packages plus the published docs, and they carry two distinct expired premises:
- (a)
member_defaulthas a'*'object grant — removed bymember_default's*wildcard object grant (C/R/E) union-merges into every org member — app-side explicit-allow object gates are erased on three axes #5491. - (b)
member_defaultships a wildcardtenant_isolationRLS policy — retired by ADR-0095 D1 in favour of the Layer 0 tenant wall (plugin-security/tenant-layer.ts).
Measured on origin/main @ 68feaadd6, probing the real imported defaultPermissionSets: member_default.objects['*'] is undefined, and its object keys are 23 explicitly named sys_* tables plus sys_user_preference — no wildcard.
CHANGELOG files and content/docs/releases/ also match the grep and are correctly frozen: they are historical records of what was true then. They are not part of this finding.
Part 1 — stale prose in live source (observation-class)
packages/platform-objects/src/identity/sys-scim-provider.object.ts:40 — premise (a):
without it, the
member_defaultwildcard'*': allowReadwould expose SCIM connections to every authenticated user
packages/platform-objects/src/identity/sys-sso-provider.object.ts:38 — premise (b) — and :43 — premise (a):
without it, the
member_defaultwildcardtenant_isolationRLS denies every row
without it, tenancy-disabled +member_default's'*': allowReadwould leak providers to every authenticated user
packages/qa/dogfood/test/rls-multitenant.dogfood.test.ts:7 — premise (b):
member_defaultscopes rows with a wildcardtenant_isolationpolicy
These are load-bearing rationale comments, not decoration: each one justifies why a requiredPermissions gate exists by naming the exposure it prevents. A reader who checks the named exposure finds it absent and may conclude the gate is redundant. The gates are almost certainly still right for other reasons (ADR-0066 D3 admin-only config), but the stated reason has expired — the validate-security-posture.ts hazard #6628 cites, one layer out.
content/docs/permissions/index.mdx:47 states as current fact:
The default
member_defaultset ships the wildcard tenant-isolation RLS (organization_id == current_user.organization_id)
which contradicts content/docs/releases/implementation-status.mdx:294 and :435 in the same repo, both of which say that policy "was retired". A published doc asserting the opposite of the status page is worth more than a naming fix.
Part 2 — two dogfood tests whose stated proof may now be vacuous
This is the part that may not be observation-class, and the reason this issue is unlabeled.
packages/qa/dogfood/test/showcase-default-profile.dogfood.test.ts:50 and packages/qa/dogfood/test/showcase-d7-default-profile.dogfood.test.ts:55 are both titled and NOT by the built-in member_default wildcard (...), and both carry the same inline rationale:
member_defaulthas a wildcard grant → would be 200. The declared default grants only announcement → this object is denied, proving D7 is in effect.
The assertion is expect(r.status).not.toBe(200). Its evidential value rests entirely on the named counterfactual: the object is denied despite a baseline that would otherwise have allowed it. Since #5491 that baseline grants nothing on app objects at all, so a non-200 is now the trivially expected outcome whether or not the app's declared default profile is in force — which is the exact thing these tests exist to prove. If that reading is right, both tests still pass while no longer demonstrating D7, and the fixture would need replacing rather than re-wording (the #5046 "replace wholesale" disposition: the assertion keeps passing because nothing is produced, not because the logic is right).
Not verified by running them — the dogfood suite needs a live stack and this was out of scope for #6842's PR. The reading above is from the source and the measured array only, and it should be confirmed before being acted on. If it is wrong, Part 2 collapses into Part 1 and this is all prose.
Why it stayed silent
The same reason #6842 gives: nothing mechanically relates "prose names set X as having shape Y" to what defaultPermissionSets ships. PR #6958 adds a pin for that relation in plugin-security, but it deliberately watches only two surfaces (audience-anchors.test.ts and the describeHighPrivilegeBits JSDoc), because those were the two #6842 named. Its watchedSurfaces() is a one-line-per-surface list and any of the files above could be added to it — but whether the pin should grow a repo-wide surface, and whether platform-objects / qa should depend on plugin-security to get one, is a scoping decision for triage rather than something to assume.
Related: #6842 and PR #6958 (this issue's origin), #6696 / PR #6846 (the spec half), #5491 / PR #6684 (cause (a)), ADR-0095 D1 (cause (b)), #6628 (the pin idiom).
🤖 Generated with Claude Code
Activity
os-project-manager commentedon Aug 9, 2026
Triage (maintainer-authorized one-off pass, 2026-08-09 — registered on #6015): graded
finding, routeddomain:identity(the drift's subject ismember_default/permission-set shape; the sibling fixes #6842/#6696 ran in the identity lane).platform-objects/qaprose + thecontent/docs/permissions/index.mdxsentence contradicting the status page) is observation-class prose drift — real, but no behaviour wrong. The docs contradiction is the sharpest piece and rides whichever card executes.member_default's*wildcard object grant (C/R/E) union-merges into every org member — app-side explicit-allow object gates are erased on three axes #5491) is the potential defect, and the filer is explicit it is unverified (needs a live-stack run). Restart condition, per the filing's own terms: a live-stack run of the twoshowcase-*-default-profiledogfood tests with the baseline question instrumented — if the counterfactual is confirmed vacuous, Part 2 promotes topm:queueas a fixture-replacement card (fix(lint): 收敛 validate-expressions / validate-security-posture 的 spec 不声明键??别名读法 (#5017) #5046 wholesale-replace shape); if not, the whole card is prose and executes as one docs/comment sweep.pm:queueprecisely because the filer declined to pre-grade — honoring that; the verification IS the next action.audience-anchors.test.tsstill namesmember_defaultas the plain-wildcard shape — the same stale illustration #6696 fixes, one package over #6842 (dispatched) covers only the twoplugin-securitysurfaces; no overlap.Generated by Claude Code
os-zhuang commentedon Aug 10, 2026
Finding-triage ruling: Promote —
findingtopm:queue.member_default's removed wildcard is still asserted as live fact at six-plus named locations — including the published permissions doc (permissions/index.mdx tenant-isolation sentence), a security-semantics page contradicting shipped behavior today. Part 1 (named-location prose sweep) is mechanically dispatchable; Part 2 (verify the two dogfood tests aren't vacuous) rides it, per the 08-09 grading.
Release-board four-class check: hits class ④ — published security docs that would need a release-notes apology.
target:v17added.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
os-zhuang commentedon Aug 10, 2026
Claim — identity-lane PM seat (#6022), session
session_01BM1tNf5U3nEbHKR4fo5qVQ. Dispatching to anos-devsubagent now.claude/issue-6964-member-default-wildcard-prose../objectstack-issue-6964(dedicated per-task worktree; never the shared checkout)domain:identity+target:v17— labels untouched (single-producer rule; promoted and boarded by the finding-triage round 00:12Z)pm:queue→pm:dispatched. Thread re-read before claiming: two comments, both triage grading, no dev claim and no competing session ID.target:v17card, and the maintainer's standing instruction is v17 first.Serial constraints cleared: the lane has nothing in flight. The sibling that covered the two
plugin-securitysurfaces (#6842 → PR #6958) landed 07:01Z and this card is explicitly the non-overlapping remainder, four packages further out.plugin-securityis not in this card's file face.Scope carried to the claimant, exactly as the triage grading split it:
packages/platform-objects(sys-scim-provider.object.ts:40,sys-sso-provider.object.ts:38+:43),packages/qa/dogfood(rls-multitenant:7,showcase-default-profile:8/50/52,showcase-d7-default-profile:8/55/57), andcontent/docs/permissions/index.mdx:47. Two distinct expired premises are mixed in there — (a) the'*'grant removed bymember_default's*wildcard object grant (C/R/E) union-merges into every org member — app-side explicit-allow object gates are erased on three axes #5491, (b) the wildcardtenant_isolationRLS retired by ADR-0095 D1 — and they must not be conflated.showcase-*-default-profiledogfood tests justify anot.toBe(200)assertion by the counterfactual "member_defaulthas a wildcard grant → would be 200". Sincemember_default's*wildcard object grant (C/R/E) union-merges into every org member — app-side explicit-allow object gates are erased on three axes #5491 that baseline grants nothing on app objects, so a non-200 may now be the trivially expected outcome whether or not the app's declared default profile is in force — the fix(lint): 收敛 validate-expressions / validate-security-posture 的 spec 不声明键??别名读法 (#5017) #5046 "replace wholesale" shape, where an assertion passes because nothing is produced. The filer marked this unverified and said so; the triage grading made the verification the restart condition. It is the load-bearing deliverable of this dispatch, not an optional extra.⛔ Boundaries:
content/docs/releases/.implementation-status.mdx:294/:435say the wildcardtenant_isolationpolicy was retired and are correct;content/docs/permissions/index.mdx:47contradicts them and is the side that must move.CHANGELOG.mdfiles andreleases/history rows matched the same grep and are correctly frozen historical records — excluded by the filing and by this dispatch.audience-anchors.test.tsstill namesmember_defaultas the plain-wildcard shape — the same stale illustration #6696 fixes, one package over #6842's twoplugin-securitysurfaces; they landed.Note for the claimant: the repo carries a
dogfood-verificationskill for booting a real example app and driving it — Part 2's answer needs a live stack, and "I could not run it, here is why" is an acceptable report only if you say what you tried. A green suite is not evidence here; that is precisely the failure mode this card is about.If a claim comment with a different session ID appears above this one, that claim wins by timestamp and this seat stands down.
Generated by Claude Code
fix(qa,platform-objects,docs): re-premise member_default's removed wi…