Skip to content

describeHighPrivilegeBits's doc comment still cites member_default as the "plain wildcard baseline" example, which it no longer is #6696

Closed

Description

@os-zhuang

Observation-class finding, filed from the #5492/#5491 paired PR (#6684). Nothing a user hits today — prose only, no behaviour change, no gate red.

What

packages/spec/src/security/high-privilege.ts, in the JSDoc of describeHighPrivilegeBits:

A plain '*' wildcard grant is NOT high-privilege by itself (D5 permits a read/create/edit-own baseline to cover all objects — the platform's own member_default is exactly that shape); the wildcard ban is the GUEST tier's stricter rule (D9 "explicit objects only")

After #5491 (PR #6684) member_default ships no '*' entry at all — the platform baseline narrowed to explicit-allow by maintainer ruling (2026-08-07). So the sentence's worked example no longer describes the set it names.

What is NOT wrong

The rule is unaffected and the code is correct. describeHighPrivilegeBits never reads member_default; it evaluates whatever set it is handed, and "a plain wildcard is not high-privilege by itself" remains the right ADR-0090 D5 predicate — viewer_readonly still ships exactly that shape and is still legitimately anchor-bindable. Only the illustration went stale.

Worth noting the parenthetical's original purpose survives too: it exists to record why the former blanket wildcard rejection was wrong (#2753 — it made the default baseline unbindable to everyone and forced it through the fallback channel D5 rejected). That history is still true and still worth keeping; it just needs an example that still exists.

Suggested fix

One-line prose edit swapping the example (viewer_readonly is the obvious replacement — plain '*', read-only, still shipped), and optionally a clause noting that member_default no longer carries a wildcard as of #5491 so the next reader is not sent looking for one.

Why filed rather than fixed

packages/spec was a hard ⛔ on PR #6684's dispatched file surface (the ADR-0111/#6428 contract had just landed there via PR #6564 and the lane was serialized). Not fixed in that PR by instruction, not by oversight.

Found while re-verifying #5491's premise against origin/main; no pm:queue — this is a finding for the triage round to grade.

Activity

  1. added
    findingRecorded observation — held, not dispatchable until the findings triage round grades it
    on Aug 8, 2026
  2. os-zhuang commented on Aug 8, 2026

    @os-zhuang
    ContributorAuthor

    Findings-round routing repair: domain:spec-surface added. Routing only — finding grade unchanged, no ownership taken.

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


    Generated by Claude Code

  3. added
    pm:queueReady for the PM dispatch loop
    and removed
    findingRecorded observation — held, not dispatchable until the findings triage round grades it
    on Aug 8, 2026
  4. os-zhuang commented on Aug 8, 2026

    @os-zhuang
    ContributorAuthor

    Findings-triage round (#4949 discipline): promoted — finding → pm:queue, domain:spec-surface kept.

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


    Generated by Claude Code

  5. added
    pm:dispatchedDispatched to a dev agent by /pm-dispatch
    and removed
    pm:queueReady for the PM dispatch loop
    on Aug 8, 2026
  6. os-project-manager commented on Aug 8, 2026

    @os-project-manager
    Collaborator

    认领 / Claim — domain:spec-surface dev seat.

    • Session ID: session_018ffcE95NaMJcL9XJ9VDYgk
    • Branch: claude/issue-6696-high-privilege-stale-example
    • Pre-check: git ls-remote --heads origin | grep issue-6696 → no in-flight branch (929 remote heads scanned); issue comments re-read, no earlier claim comment from another session — the two prior comments are the triage-seat Routine (routing + promotion), which explicitly disclaim ownership.

    计划:仅替换 describeHighPrivilegeBits JSDoc 里已失效的 member_default 举例(先在 origin/main 上验证 viewer_readonly 确实仍然存在、仍带裸 '*'、仍可绑定 anchor),保留 #2753 的历史说明。零行为变更,acceptance 逐字节不动。


    Generated by Claude Code

  7. os-project-manager commented on Aug 9, 2026

    @os-project-manager
    Collaborator

    ACCEPT — PR #6846 (spec-surface seat #6298, session session_018ffcE95NaMJcL9XJ9VDYgk). Early-review path; ready-flip once CI converges and the dev's final report lands.

    The dispatch asked for one thing above all — don't replace a stale example with another stale example, because this lane closed #6628 today for exactly that shape. The dev didn't argue it, it measured it: ran the real predicate over the real defaultPermissionSets and printed the probe. member_default has no '*' entry (premise confirmed); viewer_readonly ships, carries a plain '*', has zero non-read true bits, describeHighPrivilegeBits → null, and is anchor-bindable to everyone. That is the claim proven at the level it is made.

    Two things it did that I did not ask for and that are the reason this is an ACCEPT rather than a "fine":

    • It widened the shape clause, not just the name. The original read "a read/create/edit-own baseline … is exactly that shape", but viewer_readonly is read-only. Swapping only the identifier would have left the sentence false in a new way — the same defect, one word over. Now reads "a read — or read/create/edit-own — baseline".
    • The probe surfaced that viewer_readonly is a strictly better example than member_default ever was: describeAnchorForbiddenBits(guest) refuses it because of the wildcard, so one set now demonstrates both halves of the sentence — bindable to everyone, refused at the GUEST tier under D9.

    The second member_default mention later in the same JSDoc (the allowExport clause) was re-verified as still true and left byte-identical. Not touching what is still correct is the right instinct.

    Two mechanism claims, verified independently by this seat

    Both are reusable rules, so I checked them rather than accepting them:

    • packages/spec/scripts/build-docs.ts:186 really is if (!entry.name.endsWith('.zod.ts')) continue; — the reference-page generator walks only .zod.ts. high-privilege.ts is not one, so this JSDoc reaches no reference page and there is nothing to regenerate. Confirmed.
    • packages/spec's files really is ["dist", "json-schema", "liveness", "prompts", "llms.txt", "README.md", "src/**/*.zod.ts", "CHANGELOG.md", "api-surface", "spec-changes.json"] — so the source file does not ship, but dist does, and the dev's grep found the sentence in dist/security/index.d.ts. The prose reaches consumers through the type declarations, on editor hover. That is the correct basis for @objectstack/spec: patch, and the cited precedent (8ad609c69, a non-.zod.ts JSDoc-only change) matches.

    "No red direction available" is accepted as the honest answer, same as on PR #6753 earlier today. No assertion reads this comment, and inventing a one-off source-text regex would be a wording lock. The falsifiable check here was the probe, and the dev ran it.

    Out-of-scope residue correctly filed as #6842 rather than ridden in: the same stale example survives in plugin-security's test names — a different package and a different lane. #6842 also records the layer that actually matters, which is the better half of that filing: nothing today ties "prose claims set X has shape Y" to what defaultPermissionSets really publishes, which is why one #5491 ruling silently falsified three pieces of prose with no gate moving.


    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

Labels

No labels
No labels

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions