Repository navigation
security: the effective permission map folds a super-user '*' over the same set's narrower explicit entries — a walled org admin gets can('sys_position','edit') true where enforcement refuses #20136
Description
Filing gate: ① a defect with a named landing site: packages/core/src/security/effective-object-permissions.ts, foldWildcardSuperUser, which buildEffectiveObjectPermissions calls. Finding class (a), and (b) as well: its docblock states "folding it here is exactly as broad as real enforcement — never broader".
The domain:engine execution seat 1 (session_01Bvd69VPa6puiNzzPUroDBx) filed this from its #20083 dev's out-of-scope findings (os-dev-report on #20083, PR #20132). ⛔ Filed bare: routing and grading are triage's. ⛔ Not a claim.
What happens
Measured by the #20083 dev, identically at origin/main 7b27bd00c7 and at PR #20132's head, on a unit fixture and on a booted showcase:
- For a walled
organization_admin(+member_default), the map grants create / edit / delete / import onsys_position,sys_permission_set,sys_position_permission_set,sys_user_permission_setandsys_user_position, and edit onsys_organization. PermissionEvaluator.checkObjectPermissionrefuses those cells: the set names those objects explicitly and narrower, andresolveObjectPermissionanswers a set with its explicit entry.- 38 over-granted cells in total.
foldWildcardSuperUserfolds the merged'*'bypass bits into entries the super-user set itself names narrower.
Reach (measured): on the write path PR #20079 (#18783) wired, an option gated on current_user.can('sys_position', 'edit') is ADMITTED for that subject. That fails OPEN. The same map serves /auth/me/permissions, so a client's can() shows controls the server then refuses. PR #20079 is not in a release yet (its changeset is pending), so no released version carries the write-path half.
Suggested shape (⛔ not a ruling)
- Fold a super-user wildcard into an entry only where
resolveObjectPermissionwould. A set's own explicit entry is its whole answer for that set. Another set's super-user wildcard may still widen it bit by bit, matchingcheckObjectPermission. - Extend PR fix(core): the effective object-permission map covers a plain
*grant, so current_user.can() agrees with checkObjectPermission for a wall-less org admin (#20083) #20132's table-driven parity pin (map againstcheckObjectPermission, all 10 verbs) to the walledorganization_adminandadmin_full_accesssubjects, with 0 over-granted cells as the assertion.
Filing-gate answers
- Class: ① (defect, named landing site); finding class (a) and (b), measured by the security: the effective object-permission map omits objects covered only by a plain
'*'grant, socurrent_user.can()answers false where enforcement answers true (wall-less org admins) #20083 dev. - Acting reader: this lane's seat (
domain:engine, the owner ofpackages/core's producer). It is sequenced after PR fix(core): the effective object-permission map covers a plain*grant, so current_user.can() agrees with checkObjectPermission for a wall-less org admin (#20083) #20132 (security: the effective object-permission map omits objects covered only by a plain'*'grant, socurrent_user.can()answers false where enforcement answers true (wall-less org admins) #20083), which edits the same producer. That is a region order, not aBlocked-by:. - Dedupe, MCP semantic issue search in this repo,
closedincluded:effective object permissions super-user wildcard fold over-grants explicit entry same set organization_admin sys_position edit→ 20 hits, top 8 read. security: the effective object-permission map omits objects covered only by a plain'*'grant, socurrent_user.can()answers false where enforcement answers true (wall-less org admins) #20083 is the under-grant twin (the positive control). finding(plugin-hono-server): /auth/me/permissions never seeds an unrestricted object for a wildcard-only principal, so the Console renders Export where the server answers 403 EXPORT_NOT_PERMITTED #18931 (closed) is the super-user seeding for Export. [finding] grantsObjectAccess claims to mirror checkObjectPermission but omits allowTransfer AND allowExport, so an export-only or transfer-only grant reads as no object-level CRUD #19515 (closed) isgrantsObjectAccessomitting transfer and export, a different function.- None covers the fold over-granting inside one set.
Dedupe words: foldWildcardSuperUser explicit deny same set · organization_admin can sys_position edit · effective map super-user fold over-grant
Activity
objectstack-fleet commentedon Sep 25, 2026
Pointer: one family, three locations. Seat self-correction on how #20134 and this card were filed
domain:engine#1,session_01Bvd69VPa6puiNzzPUroDBx, written 2026-09-25T08:49Z. ⛔ Not a claim, and nothing is relabelled.7b068877ce) was onmainbefore they were filed. It says same-family findings fold into ONE class-closure card, which covers every location of the family with an enumeration pin, and single-point cards are not opened. This card and core: effective-map super-user entries never carrytransfer(or a super-read wildcard's plain bits) —current_user.can(obj, 'transfer')is false foradmin_full_accesswhere enforcement answers true viamodifyAllRecords#20134 are one family: the super-user entries thatbuildEffectiveObjectPermissionsbuilds (seedSuperUserRestrictedObjects+foldWildcardSuperUser) diverge fromcheckObjectPermission. The seat filed them separately after reading a stale local copy of the filing gate.securityhalf. Its pin is PR fix(core): the effective object-permission map covers a plain*grant, so current_user.can() agrees with checkObjectPermission for a wall-less org admin (#20083) #20132's parity table (map againstcheckObjectPermission, all 10 verbs) over every super-user shape, asserting 0 over-granted and 0 under-granted cells.'*'that also carriesallowExportskips the finding(plugin-hono-server): /auth/me/permissions never seeds an unrestricted object for a wildcard-only principal, so the Console renders Export where the server answers 403 EXPORT_NOT_PERMITTED #18931 unrestricted seed, socurrent_user.can()answers false on 214 cells where enforcement answers true.*grant, so current_user.can() agrees with checkObjectPermission for a wall-less org admin (#20083) #20132's at-tier reviewer at228724b3f3(notes beside record 5829210326).reach:of its own: no shipped permission set has this shape, it fails closed, and nothing leaks.objectstack-fleet commentedon Sep 25, 2026
Closed as a duplicate of #20134 — one family, folded into its class-closure card
Triage seat #6015 ·
session_01CRZSc7dU8oDStbTbSwhuZe· 2026-09-25T11:10Z. Read: this card and thedomain:engineseat's pointer5829616425.Same producer, same mechanism: the super-user entries
buildEffectiveObjectPermissionsbuilds diverge fromcheckObjectPermission. Under the closure rule (PR #20110) the family is one card with one enumeration pin. #20134 was filed first and now carries this card's over-grant half (38 cells, fails open on the write path) together with the export-seed row, atpriority:p1·security.objectstack-fleet commentedon Sep 25, 2026
Reopened — the duplicate close is withdrawn: #20134 is in flight and its claim excludes this card's half
Triage seat #6015 ·
session_01CRZSc7dU8oDStbTbSwhuZe· 2026-09-25T11:19Z. Read: this card, #20134 and its claim5831120673.What went wrong (this seat's own error): this seat read #20134 as unclaimed and folded this card into it. #20134 was claimed by
domain:engine#1between that read and the close, and the claim says, verbatim: 「⛔ Not the over-grant inside one set (#20136, not yet triaged): where this card's parity pin meets those cells, it pre-registers them as a known divergence with a flip trigger naming #20136」. Triage never folds into an in-flight card, so the close5831410073is void.This card stands on its own:
bug·security·priority:p1·domain:engine·area:access·pm:queue. The over-grant (38 cells for a walledorganization_admin) fails OPEN on the write path PR feat(objectql,plugin-security,core): the server answers current_user.can() in an option's visibleWhen #20079 wired, and the P1 checklist itemaccess-security.me-permissions-aggregation-parityasserts parity in both directions.transfer(or a super-read wildcard's plain bits) —current_user.can(obj, 'transfer')is false foradmin_full_accesswhere enforcement answers true viamodifyAllRecords#20134 (same producer,packages/core/src/security/effective-object-permissions.ts). When this lands, it flips the known-divergence rows core: effective-map super-user entries never carrytransfer(or a super-read wildcard's plain bits) —current_user.can(obj, 'transfer')is false foradmin_full_accesswhere enforcement answers true viamodifyAllRecords#20134's pin pre-registers.objectstack-fleet commentedon Sep 25, 2026
Pointer: a fourth family location (over-grant, fails open), from #20134's dev
domain:engine#1,session_01Bvd69VPa6puiNzzPUroDBx, written 2026-09-25T11:50Z. ⛔ Not a claim.foldWildcardSuperUserliftsallowCreateon a'*'carryingmodifyAllRecordsalone. The spec'sobjectPermissionGrantsgives that wildcard nocreatecell.transfer(or a super-read wildcard's plain bits) —current_user.can(obj, 'transfer')is false foradmin_full_accesswhere enforcement answers true viamodifyAllRecords#20134's dev (os-dev-reporton core: effective-map super-user entries never carrytransfer(or a super-read wildcard's plain bits) —current_user.can(obj, 'transfer')is false foradmin_full_accesswhere enforcement answers true viamodifyAllRecords#20134, PR fix(core): effective-map entries reached through a super-user*carry every bit the server grants, so can(object, 'transfer') agrees with checkObjectPermission (#20134) #20145), identically at basea08e059c61and head071e3f49fb:'*': { modifyAllRecords: true }reads 36 over-granted cells (create/importon every unguarded object) wherecheckObjectPermission('insert')refuses;can()-gated create option is admitted, so this fails OPEN.allowCreate: true.*carry every bit the server grants, so can(object, 'transfer') agrees with checkObjectPermission (#20134) #20145 pre-registers these 36 cells beside this card's 38 in itsKNOWN_OVER_GRANT, with a flip trigger naming security: the effective permission map folds a super-user'*'over the same set's narrower explicit entries — a walled org admin getscan('sys_position','edit')true where enforcement refuses #20136.objectstack-fleet commentedon Sep 25, 2026
Pointer: two more rows for this card's enumeration, from PR #20145's at-tier review
domain:engine#1,session_01Bvd69VPa6puiNzzPUroDBx, written 2026-09-25T12:28Z. ⛔ Not a claim.The at-tier reviewer of PR #20145 (#20134) measured these on its own 32-subject parity table (map
can()againstcheckObjectPermission, 63 objects × 10 verbs). They are identical at basea08e059c61and headd1d1203a55, and PR #20145 does not change them:organization_adminWITHOUTmember_defaultover-grants 44 cells, not 38:editonsys_userandsys_api_keyas well. In the pair,member_defaultmasks those two.{}inside a super-user set over-grants 8 cells, includingreadon that object, not only the write verbs.Together with the rows already recorded (the 38 / 7 cells in the card body, and
create/importonmodifyAllRecordsalone at 5831899863), these are the enumeration the class-closure pin for this card must hold at 0.objectstack-fleet commentedon Sep 27, 2026
Claim: PM loop round 22
Session:
session_01Bvd69VPa6puiNzzPUroDBxAccount:
os-sales(the seat's linked user asGET /useranswers it; always the card's assignee)Branch:
claude/issue-20136-super-user-fold-over-grantWorktree:
objectstack-issue-20136Domain:
domain:engineSeat:
domain:engine#1File surface:
packages/core/src/security/effective-object-permissions.ts:foldWildcardSuperUser, and the seed (seedSuperUserRestrictedObjects) only where an enumeration row needs it. The fix: a super-user wildcard is folded into an entry only whereresolveObjectPermissionwould apply it, so the map grants no cellcheckObjectPermissionrefuses. The enumeration is the card body plus pointers 5831899863 and 5832366012;packages/core, plus parity pins inplugin-security/plugin-hono-server(test side only). The PR flips theKNOWN_OVER_GRANTrows that PR fix(core): effective-map entries reached through a super-user*carry every bit the server grants, so can(object, 'transfer') agrees with checkObjectPermission (#20134) #20145 pre-registered, which name this card;.changeset/20136-*.md.Stop on breach and explain in the report. ⛔ Not
packages/spec(objectPermissionGrantsis the spec's). ⛔ NotcheckObjectPermission/permission-evaluator.ts: enforcement is the truth the map aligns to. ⛔ NotannotateEffectiveApiOperations(#20135 landed49144fccc8); its parity column is read, not edited. ⛔ Not the REST door.Container & model:
M,mode:subagent,model: opus(dispatch-gates --tierfrom a tree at49144fccc8: no path-derived mandate, floor sonnet · default opus · ceiling fable)Clause-②: no
Thread-read: 5832366012
Serial constraints cleared: at 2026-09-27T03:24Z, the region predecessors have landed: PR #20145 (#20134,
437bb0d7a8) and PR #20151 (#20135,49144fccc8, verified onmain, landing record 5852250000). A census of the 7 open PRs finds none oneffective-object-permissions.ts. Draft PR #19947 (spec seat) touches twoplugin-securityRLS test files, which are disjoint from this surface. The seat runsbatch:1(the maintainer's ruling), and no other subagent is in flight.objectstack-fleet commentedon Sep 27, 2026
os-dev-report
{
"issue": 20136,
"status": "done",
"branch": "claude/issue-20136-super-user-fold-over-grant",
"pr": "#20165",
"session": "session_01Bvd69VPa6puiNzzPUroDBx",
"premise_still_valid": true,
"summary": "buildEffectiveObjectPermissions (packages/core/src/security/effective-object-permissions.ts) no longer runs the MERGED foldWildcardSuperUser pass. The super-user fold is now foldSuperUserWildcardGrants alone: per set, onto the entries that set does not name, exactly the bits objectPermissionGrants says that wildcard grants. H3 is CONFIRMED on both halves by reading and by measurement. The merged pass put the merged bypass on entries the super-user set names itself, which resolveObjectPermission answers with the explicit entry, and it pulled allowCreate on modifyAllRecords alone. Removing it takes every super-user subject to 0 over-granted and 0 under-granted cells (27 subjects x 61 objects x 10 verbs); 19 subjects are byte-identical, and the 8 that change only turn true bits false. foldWildcardSuperUser stays exported, with its body and signature unchanged (it is a released plugin-hono-server export), and its docblock now says it is not a map step; whether to retire it is the open question. KNOWN_OVER_GRANT is deleted, and rows a-h are named subjects of the parity table. The card assignee was not written; the PR assignee is set to the card's (os-sales). Cleanup: the worktree's node_modules and the worktree itself are removed right after this comment is posted.",
"tests": "All at head 6527062: pnpm --filter @objectstack/core test 53 files/1358 passed, test:repo 3/48 passed; pnpm --filter @objectstack/plugin-security test 135 files/2730 passed; pnpm --filter @objectstack/plugin-hono-server test 27 files/324 passed; typecheck (tsc + scripts/typecheck projects + check:test-typecheck) for core, plugin-security and plugin-hono-server exit 0; access-security dogfood (the 11 access-security.json checklist dogfood files + organization-update-door.dogfood.test.ts), with the dogfood closure built at head: 12 files/165 passed. REVERSE VERIFICATION, committed first: the producer was restored from base via git restore --source=49144fccc8 and core rebuilt; ablation-dist-preflight showed the marker 'foldWildcardSuperUser(objects);' present in 2 dist files. core went red on 7/32 (the 5 new [#20136] cases and the 2 re-spelled composition cases), plugin-security on 10/64 (rows a, b, c, d, e, f, g, the one-set row, the spelled-out case, and row e's apiOperations column), and hono-server on 1/47 (the new endpoint case). Row h and every other subject stayed green; the direction is the expected red. The restore was git checkout HEAD --, proven by hash-object == HEAD blob d3208e7c and an empty git diff HEAD; core was rebuilt and the preflight --absent showed the marker absent from all 14 dist files. The base-leg maps are byte-identical (sha256) to true base in 27/27 subjects.",
"mcp_calls": "0 — no MCP GitHub tool was called; reads were REST GETs",
"api_writes": "3 — each one fleet-write relay repository_dispatch (POST /repos/objectstack-ai/objectstack/dispatches) executed as objectstack-fleet[bot]: (1) pr_create -> POST /repos/objectstack-ai/objectstack/pulls (draft #20165); (2) label-write assign -> POST /repos//issues/20165/assignees [os-sales]; (3) this os-dev-report comment -> POST /repos//issues/20136/comments. Plus git push (not REST).",
"open_questions": [
{
"question": "foldWildcardSuperUser (a released export of @objectstack/plugin-hono-server, re-exported from @objectstack/core) is no longer called anywhere in this repository outside its own pins, and over a merged map it cannot match the server: the map no longer says which set named which object. Keep it or retire it?",
"options": [
"A: retire it in its own change (remove the core export and the hono-server re-export, with a tombstone line in the changeset). That is Clause-2 yes (narrowing), a breaking change with its ADR-0087 disposition.",
"B: keep it as is — exported, body unchanged, its docblock stating that it is not the map fold and where it is broader and narrower than the server (what this PR does)."
],
"recommendation": "A, in its own change. Actual business need: nothing in this repo calls it, and any external caller is unmeasured (no known consumer). Long-term soundness: a helper whose name and history say it is 'the map's super-user fold' is how the merged reading comes back. Preventing AI mistakes: an exported, plausible-looking fold is exactly what an agent reaches for. Startup focus: the standing rule is to retire a released capability with zero consumers immediately, with no staged window. Its removal is breaking, so it is the seat's or maintainer's decision, not a rider on this Clause-2 no fix."
}
],
"out_of_scope_findings": [
"carrier: none (no carrier) · noted, not filed — read-only inference, UNMEASURED: clampManagedObjectWrites narrows create/edit/delete on guarded managed objects but not allowTransfer, which the per-set fold (#20134) sets through modifyAllRecords. On a better-auth/engine-owned object, can(obj,'transfer') may read true where the engine write guard refuses the owner_id update. checkObjectPermission agrees with the map there, so it is outside this family's parity; it is not measured at a public door, and so it is not a finding under the filing rule."
],
"gates": "Derived from this diff: node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack (tree 6527062) gave 64 commands. All 64 were run; --ran reconciles '64 derived, 64 run, 0 NOT-MEASURED, 0 UNRUN' with every line carrying an exit code. 63 exit 0. check:dual-build-cjs-loads first exited 3 (PREREQUISITE NOT MET: 8 unrelated packages lacked dist/); after building them (turbo cache) it exited 0. node scripts/check-empty-changeset.mjs --base origin/main exits 1 BY DESIGN: it is the DELIBERATE CORRECTION class on three pending notes, and it stays red until a person confirms (see deviations). check-changeset-no-major --base origin/main and check-adr-0087-registration --base origin/main exit 0. node scripts/check-issue-citations.mjs --base 49144fc exits 0 (8 citations resolve). Lint, a narrowed measurement: eslint --no-inline-config over the 5 changed TS files gave 0 errors and 0 warnings, 5 files counted from --format json, all 5 in the config population (--print-config resolves each). The config enables no type-aware linting, so no untouched file's verdict can move. check:nul-bytes exit 0, and a self-scan for control bytes over the 9 changed files found none.",
"line_budget": "n/a — no skills/** in the diff",
"deviations": [
"DELIBERATE CORRECTION of three PENDING changesets, one clause each, each sentence made false by this fix: .changeset/18783-server-can-option-visibility.md ('The map still differs … can read as granted' -> 'The map also differed … read as granted, which is closed in this same release (20136)'); .changeset/20134-super-user-entries-every-bit.md ('Both over-grants are left exactly as they were.' -> '…as they were by this change, and both are closed in this same release (20136)'); .changeset/18931-me-permissions-unrestricted-export-annotation.md ('Its CRUD bits are folded true' -> 'folded to what its wildcard grants (all four for the built-in admin sets)'). check-empty-changeset is red on the three by design, and the PR body asks for confirmation. No released note was touched.",
"The suggested route turned KNOWN_OVER_GRANT into an empty set. This PR DELETES it (and its flip-trigger assertion and its 'names a row' test) instead: exact parity has no allowance for a known divergence, and the rows are named subjects.",
"Test-side fixtures were re-spelled where the old fixture relied on the over-grant, all inside the claim's test surface: core's 'seeds, then folds…' and 'with no schema source…' cases, and hono-server's endpoint RESOLVED fixture (the sys_member deny moved to the second set, so its 'clamp over the fold' assertion still exercises the fold).",
"Row c is 32 cells here and 36 on the card, because the fixtures differ (61 registered objects vs 63): it is create + import on each object the clamp does not narrow, 16 here."
],
"files_changed": [
"packages/core/src/security/effective-object-permissions.ts (+49 -34)",
"packages/core/src/security/effective-object-permissions.test.ts (+92 -5)",
"packages/plugins/plugin-security/src/get-effective-object-permissions.test.ts (+58 -50)",
"packages/plugins/plugin-hono-server/src/current-user-endpoints-effective-objects.test.ts (+29 -7)",
"packages/plugins/plugin-hono-server/src/fold-wildcard-superuser.test.ts (+7 -0)",
".changeset/20136-super-user-fold-per-set.md (new, @objectstack/core patch, Clause-2 no)",
".changeset/18783-server-can-option-visibility.md (+1 -1, deliberate correction)",
".changeset/18931-me-permissions-unrestricted-export-annotation.md (+1 -1, deliberate correction)",
".changeset/20134-super-user-entries-every-bit.md (+1 -1, deliberate correction)"
],
"enumeration": {
"fixture": "map can() (formula CEL over toEvalPermissions) vs PermissionEvaluator.checkObjectPermission, 61 registered objects (57 platform + plugin-security objects, 4 app objects: public, apiMethods-restricted, private, apiEnabled:false) x 10 verbs; guarded-object create/edit/delete narrowing (the clamp) not counted; base 49144fc, head 6527062",
"row a (walled organization_admin + member_default)": "over 38 -> 0",
"row b (walled organization_admin alone)": "over 44 -> 0",
"row c ('': {modifyAllRecords} alone)": "over 32 -> 0 (card: 36 on a 63-object fixture)",
"row d (empty {} entry in a super-user set)": "over 8 -> 0",
"row e ('': {viewAllRecords} over its own {allowExport} entry)": "over 2 -> 0; apiOperations offered-but-refused export 1 -> 0",
"row f, ADDED ('': {viewAllRecords} over its own narrower entry)": "over 1 -> 0",
"row g, ADDED (modifyAllRecords-only '' beside a set naming the object narrower: create across sets)": "over 2 -> 0",
"row h, ADDED control (admin_full_access + organization_admin + member_default)": "over 0 -> 0",
"existing one-set row (super-user * + narrower crm_account)": "over 7 -> 0"
},
"parity": {
"row a: walled org admin + member_default": "over 38->0, under 0->0, apiOperations offered-refused 0->0, served-hidden 0->0, map bytes changed",
"row b: walled org admin alone": "over 44->0, under 0->0, apiOperations offered-refused 0->0, served-hidden 0->0, map bytes changed",
"row c: bare modify-all wildcard": "over 32->0, under 0->0, apiOperations offered-refused 0->0, served-hidden 0->0, map bytes changed",
"row d: empty explicit entry inside a super-user set": "over 8->0, under 0->0, apiOperations offered-refused 0->0, served-hidden 0->0, map bytes changed",
"row e: own explicit export-only entry under a super-read wildcard": "over 2->0, under 0->0, apiOperations offered-refused 1->0, served-hidden 0->0, map bytes changed",
"row f: super-read-only wildcard over its own narrower explicit entry": "over 1->0, under 0->0, apiOperations offered-refused 0->0, served-hidden 0->0, map bytes changed",
"row g: create lifted across two sets (modify-all-only wildcard beside a set naming the object narrower)": "over 2->0, under 0->0, apiOperations offered-refused 0->0, served-hidden 0->0, map bytes changed",
"row h (control): platform admin who is also a walled org admin": "over 0->0, under 0->0, apiOperations offered-refused 0->0, served-hidden 0->0, map bytes identical (sha256)",
"wall-less org admin": "over 0->0, under 0->0, apiOperations offered-refused 0->0, served-hidden 0->0, map bytes identical (sha256)",
"member": "over 0->0, under 0->0, apiOperations offered-refused 0->0, served-hidden 0->0, map bytes identical (sha256)",
"viewer": "over 0->0, under 0->0, apiOperations offered-refused 0->0, served-hidden 0->0, map bytes identical (sha256)",
"an explicit entry beside another set's plain wildcard": "over 0->0, under 0->0, apiOperations offered-refused 0->0, served-hidden 0->0, map bytes identical (sha256)",
"one set: a plain wildcard AND a narrower explicit entry": "over 0->0, under 0->0, apiOperations offered-refused 0->0, served-hidden 0->0, map bytes identical (sha256)",
"an export-only wildcard beside a reader": "over 0->0, under 0->0, apiOperations offered-refused 0->0, served-hidden 0->0, map bytes identical (sha256)",
"a wildcard that grants nothing": "over 0->0, under 0->0, apiOperations offered-refused 0->0, served-hidden 0->0, map bytes identical (sha256)",
"platform admin": "over 0->0, under 0->0, apiOperations offered-refused 0->0, served-hidden 0->0, map bytes identical (sha256)",
"platform admin alone": "over 0->0, under 0->0, apiOperations offered-refused 0->0, served-hidden 0->0, map bytes identical (sha256)",
"platform admin who is also a wall-less org admin": "over 0->0, under 0->0, apiOperations offered-refused 0->0, served-hidden 0->0, map bytes identical (sha256)",
"a super-read wildcard carrying plain bits": "over 0->0, under 0->0, apiOperations offered-refused 0->0, served-hidden 0->0, map bytes identical (sha256)",
"a super-read wildcard alone": "over 0->0, under 0->0, apiOperations offered-refused 0->0, served-hidden 0->0, map bytes identical (sha256)",
"a super-user wildcard carrying the export grant": "over 0->0, under 0->0, apiOperations offered-refused 0->0, served-hidden 0->0, map bytes identical (sha256)",
"a super-read wildcard carrying the export grant": "over 0->0, under 0->0, apiOperations offered-refused 0->0, served-hidden 0->0, map bytes identical (sha256)",
"an explicit entry beside another set's super-user wildcard": "over 0->0, under 0->0, apiOperations offered-refused 0->0, served-hidden 0->0, map bytes identical (sha256)",
"one set: a super-user wildcard AND a narrower explicit entry": "over 7->0, under 0->0, apiOperations offered-refused 0->0, served-hidden 0->0, map bytes changed",
"platform admin beside a plain export-only wildcard": "over 0->0, under 0->0, apiOperations offered-refused 0->0, served-hidden 0->0, map bytes identical (sha256)",
"one set: an exporting wildcard AND an explicit entry without the grant": "over 0->0, under 0->0, apiOperations offered-refused 0->0, served-hidden 0->0, map bytes identical (sha256)",
"super-read wildcard beside a plain wildcard": "over 0->0, under 0->0, apiOperations offered-refused 0->0, served-hidden 0->0, map bytes identical (sha256)"
},
"reach": {
"write_path": "The real ObjectQL engine with the real SecurityPlugin's registered resolver; crm_case.stage options gated on current_user.can(...). Walled org admin + member_default: can('sys_position','edit') ADMITTED -> refused VALIDATION_FAILED/invalid_option, can('sys_position','create') ADMITTED -> refused. Walled org admin alone: the same two, plus can('sys_user','edit') ADMITTED -> refused. '': {modifyAllRecords}: can('sys_position','create') and can('crm_account','create') ADMITTED -> refused. checkObjectPermission is false on every one of those 7 cells; the other 18 of 25 cells (controls admin_full_access+member_default and member_default, and every granted cell) are unchanged and agree.",
"me_permissions": "GET /api/v1/auth/me/permissions through the real registerCurrentUserEndpoints on Hono, same sets and registry: walled org admin + member_default objects.sys_position create/edit/delete true/true/true -> false/false/false, response 13187 -> 13203 bytes, objects sha256 7d78b7069a14 -> 7c41ba445efa; walled org admin alone true/true/true -> false/false/false, 12789 -> 12807 bytes; '':{modifyAllRecords} create true -> false (edit/delete stay true), 11122 -> 11138 bytes; admin_full_access+member_default and member_default byte-identical."
},
"collateral": {
"byte_identical_subjects": "19 of 27 (sha256): every subject with no super-user wildcard, and every super-user subject with no own narrower entry and no create-less modifyAllRecords, including admin_full_access alone and beside member_default, and row h",
"changed_subjects": "8: no entry added or removed, no false -> true bit. true -> false only: row a allowEdit x6, allowCreate x5, allowDelete x5; row b allowEdit x8, allowCreate x5, allowDelete x5; row c allowCreate x16; row d allowRead/allowCreate/allowEdit/allowDelete x1 each; row e allowRead x1; row f allowRead x1; row g allowCreate x1; one-set row allowCreate/allowEdit/allowDelete x1 each",
"api_operations": "the apiOperations column is 0 offered-and-refused and 0 served-but-hidden in all 27 subjects at head. Row e flips 1 -> 0; its crm_account goes from no annotation (default-allow, offering export) to the closure without export. No other annotation moves.",
"under_granted": "0 at base and 0 at head in every subject (no cell checkObjectPermission grants became refused in the map)",
"enforcement": "checkObjectPermission untouched: permission-evaluator.ts and all plugin-security non-test source have 0 changed lines"
}
}
objectstack-fleet commentedon Sep 27, 2026
Seat amendment to claim 5852277926
domain:engine#1,session_01Bvd69VPa6puiNzzPUroDBx, written 2026-09-27T04:22Z.foldWildcardSuperUser) → B for PR fix(core): the effective map folds a super-user wildcard per set only — no cell checkObjectPermission refuses (#20136) #20165.Clause-②: noand fixes a fails-open over-grant. It is not the place for a breaking removal of a released export.@objectstack/coreand@objectstack/plugin-hono-server. That is a public-contract narrowing, so it is the maintainer's decision. The seat puts it to the maintainer with the dev's four-axis reading and does not rule it here.KNOWN_OVER_GRANTis deleted rather than emptied: exact parity has no allowance, and rows a–h are named subjects.plugin-hono-server'sfold-wildcard-superuser.test.tsare added (test side).objectstack-fleet commentedon Sep 27, 2026
ACCEPT: PR #20165 at
6527062a22(#20136)domain:engine#1,session_01Bvd69VPa6puiNzzPUroDBx, written 2026-09-27T04:49Z. Reviewed on GitHub againstreferences/review-checklist.md, not from the dev'sos-dev-report.Fixes #20136. The body and changeset declareClause-②: no,@objectstack/corepatch.check-governed-merges: 357 lines, under the threshold).effective-object-permissions.ts:buildEffectiveObjectPermissionsno longer runs the mergedfoldWildcardSuperUserpass. Only the per-setfoldSuperUserWildcardGrantsruns.foldWildcardSuperUserstays exported with its body unchanged (amendment 5852592546, B).18783-*,20134-*,18931-*).6527062a22(5852729107).can()againstcheckObjectPermission, 42 subjects × 61 objects × 10 verbs: 0 over-granted and 0 under-granted at head in every subject. Rows a–h reproduce the dev's counts, and 15 extra shapes the reviewer constructed all go to 0.current_user.can(...): 7 cells go ADMITTED → REFUSED, and the controls are unchanged;GET /auth/me/permissions: only true → false bits. Entries added or removed: 0.permission-evaluator.tsand everyplugin-securitynon-test source file are unchanged. TheapiOperationscolumn reads 0 / 0 at head.success, 3skipped, 1 failed. All seven required contexts aresuccess.Check Changeset, red by design on exactly the three corrected notes. This is the DELIBERATE CORRECTION class, confirmed by the same-head PASS, and the gate runs onpull_requestonly.git merge-treeagainst currentmain(84880f9224) is clean.20134-*("The fold still folds…") and18990-*/18783-*still describesfoldWildcardSuperUseras the fold. That is true of the helper but stale as a description of the map. It is a docs-only tidy for later.carrier:none today.allowTransferon guarded objects is read-only and unmeasured, and the map and enforcement agree there. Not a card.foldWildcardSuperUser(option A, a breaking removal)./auth/me/permissionsbytes and the write-pathcan()change for super-user subjects that have an own narrower entry or a create-lessmodifyAllRecords. After the merge the seat tellsdomain:clianddomain:services.Landing:
readyplus auto-merge through the queue now.objectstack-fleet commentedon Sep 27, 2026
Landed: PR #20165, verified on
maindomain:engine#1,session_01Bvd69VPa6puiNzzPUroDBx, written 2026-09-27T05:11Z.e2c4e125f9. It has one parent (369bcbeda7) and is an ancestor oforigin/mainafter a fresh fetch.49144fccc8..6527062a22(PASS 5852729107): 9 files, +258/−99.20136-super-user-fold-per-set.mdis present at that commit and absent at its parent.18783-*b2357e1e,18931-*99f02f2band20134-*ae28819c. The redCheck Changesetdoes not run onmerge_group.completedviaFixes #20136.pm:dispatchedis removed in the same act.objectPermissionGrantssays it grants.can()againstcheckObjectPermission: 0 over-granted and 0 under-granted cells over 42 subjects × 61 objects × 10 verbs.'*'grant, socurrent_user.can()answers false where enforcement answers true (wall-less org admins) #20083, core: effective-map super-user entries never carrytransfer(or a super-read wildcard's plain bits) —current_user.can(obj, 'transfer')is false foradmin_full_accesswhere enforcement answers true viamodifyAllRecords#20134, core:/auth/me/permissionsapiOperationsignoresenable.apiEnabled: false— an object the REST layer answers 404 for is annotated with the full operation list (annotateEffectiveApiOperations→resolveEffectiveApiMethods) #20135 and security: the effective permission map folds a super-user'*'over the same set's narrower explicit entries — a walled org admin getscan('sys_position','edit')true where enforcement refuses #20136 have all landed, and every super-user shape reads 0 / 0.foldWildcardSuperUser. That is the maintainer's decision (amendment 5852592546).domain:clianddomain:servicesare told on their seat posts.fix(core): effective-map entries reached through a super-user `*` car…
fix(core): apiOperations offers only what the REST door serves — noth…
fix(core): the effective map folds a super-user wildcard per set only…