Symptom
Package-seeded sharing rules are invisible and unmanageable through the admin API. Stock boot, admin bearer:
GET /api/v1/sharing/rules → 200 {"data":[]} though sys_sharing_rule lists 4 active seeded rules.
GET /api/v1/sharing/rules/share_red_projects_with_execs → 404 RULE_NOT_FOUND.
POST …/<name>/evaluate → 404.
- Control:
POST /api/v1/sharing/rules/srule_<row id>/evaluate → 200 {matchedRecords:1, expandedUsers:2, grantsCreated:1}.
Confirming experiment: a rule created via the API (where defineRule stamps organization_id from the same context) is findable by name, listed, and evaluable by name.
Enforcement is unaffected — the boot reconcile uses SYSTEM_CTX, which carries no org — which is exactly why this stayed invisible.
Root cause
Located by the run. packages/plugins/plugin-sharing/src/sharing-rule-service.ts applies a strict-equality org filter that package-seeded rows cannot satisfy: listRules does if (orgId) where.organization_id = orgId (~L234), and getRule's name fallback is orgId ? {name, organization_id: orgId} : {name} (~L255). Package-seeded rows carry organization_id = null while an authenticated admin's context carries organizationId='org_…', so only the unfiltered by-id branch survives. Confirmed present on origin/main.
Reproduction
- Stock showcase boot with 4 package-seeded sharing rules present in
sys_sharing_rule.
- As admin:
GET /api/v1/sharing/rules → empty; GET /api/v1/sharing/rules/<seeded name> → 404; by-id evaluate → 200.
Suggested fix
Treat package-seeded (organization_id = null) rows as visible to an org-scoped admin — e.g. match organization_id = orgId OR organization_id IS NULL in listRules/getRule, mirroring how enforcement reads them under SYSTEM_CTX.
Source
Extracted from the QA run #7637 (framework 92f26f7, console 09987b680).
Symptom
Package-seeded sharing rules are invisible and unmanageable through the admin API. Stock boot, admin bearer:
GET /api/v1/sharing/rules→ 200{"data":[]}thoughsys_sharing_rulelists 4 active seeded rules.GET /api/v1/sharing/rules/share_red_projects_with_execs→ 404RULE_NOT_FOUND.POST …/<name>/evaluate→ 404.POST /api/v1/sharing/rules/srule_<row id>/evaluate→ 200{matchedRecords:1, expandedUsers:2, grantsCreated:1}.Confirming experiment: a rule created via the API (where
defineRulestampsorganization_idfrom the same context) is findable by name, listed, and evaluable by name.Enforcement is unaffected — the boot reconcile uses
SYSTEM_CTX, which carries no org — which is exactly why this stayed invisible.Root cause
Located by the run.
packages/plugins/plugin-sharing/src/sharing-rule-service.tsapplies a strict-equality org filter that package-seeded rows cannot satisfy:listRulesdoesif (orgId) where.organization_id = orgId(~L234), andgetRule's name fallback isorgId ? {name, organization_id: orgId} : {name}(~L255). Package-seeded rows carryorganization_id = nullwhile an authenticated admin's context carriesorganizationId='org_…', so only the unfiltered by-id branch survives. Confirmed present onorigin/main.Reproduction
sys_sharing_rule.GET /api/v1/sharing/rules→ empty;GET /api/v1/sharing/rules/<seeded name>→ 404; by-id evaluate → 200.Suggested fix
Treat package-seeded (
organization_id = null) rows as visible to an org-scoped admin — e.g. matchorganization_id = orgId OR organization_id IS NULLinlistRules/getRule, mirroring how enforcement reads them underSYSTEM_CTX.Source
Extracted from the QA run #7637 (framework 92f26f7, console 09987b680).