You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
ADR-0056 D6 added the role_and_subordinates sharing-rule recipient (configurable role-hierarchy widening), implemented in @objectstack/plugin-sharing (role-graph.tsRoleGraphService + sharing-rule-service.tsexpandRecipient) and covered by the plugin's own unit tests.
While trying to demonstrate D6 in the showcase (as part of #2076), I found a deeper, pre-existing architectural gap that blocks it from being shown end-to-end.
The gap
Stack-declared roles and sharingRules are never seeded into sys_role / sys_sharing_rule at runtime — neither by the verify harness (bootStack) nor by the real pnpm dev CLI (packages/cli/src/commands/serve.ts).
Evidence:
Booting the showcase via bootStack yields sys_role count = 0 and sys_sharing_rule count = 0, even though the showcase declares 3 roles + 2 sharing rules.
SharingServicePlugin.start() binds rule hooks from ruleService.listRules(), which reads the sys_sharing_rule table — but nothing populates that table from app metadata. Boot logs show [sharing-rule] hooks bound {"objects":[],"ruleCount":0}.
A repo-wide search finds no code path that inserts stack-declared roles/sharingRules into sys_role/sys_sharing_rule (only the runtime createRule API at sharing-rule-service.ts:138 writes the table).
Consequence: the showcase's existing declarative roles + sharing rules (and any app's, e.g. examples/app-crm) are decorative — Studio/authoring metadata that never enforces at runtime. This is a classic enforce-or-remove (ADR-0049) situation.
Note: this is distinct from permission sets, which do resolve at runtime via metadataService.list('permission') / sys_permission_set (permission-evaluator.ts resolvePermissionSets). D7's app-declared default profile was wired through the CLI in #2076 precisely because permission sets resolve; roles + sharing rules do not.
Proposed work
Seed (idempotent upsert) stack-declared roles → sys_role and sharingRules → sys_sharing_rule at boot, so the existing sharing-rule evaluator (rule-hooks.tsafterInsert/afterUpdate) activates them.
Likely homes: SecurityPlugin for roles (sys_role), SharingServicePlugin for sharing rules (sys_sharing_rule), reading from metadataService.list('role' / 'sharingRule').
Must be idempotent (re-seed on each boot without duplicating), and reconcile updates/removals.
Decide org-scoping behavior (per-tenant seeding under plugin-org-scoping).
⚠️ Blast radius — needs its own ADR + careful review
This changes enforcement behavior for every app that declares roles/sharing rules (examples/app-showcaseandexamples/app-crm today). Activating previously-inert rules can change who-can-see-what. Requires:
A full dogfood-suite run across all example apps (currently green precisely because rules are inert).
An ADR documenting the enforce-or-remove decision and migration/rollout posture.
Acceptance criteria
ADR for "activate declarative roles + sharing rules at runtime".
Stack-declared roles + sharing rules seeded idempotently into sys_role / sys_sharing_rule at boot (verify harness + CLI).
Full dogfood suite green across all example apps; any behavior changes intentional + documented.
Showcase D6 demo: add a role_and_subordinates sharing rule + a conventional role hierarchy (exec → manager → contributor), with an end-to-end dogfood proof that a manager + their subordinates gain access via the widening.
References
ADR-0056 (permission model landing verification); D6 section.
Background
ADR-0056 D6 added the
role_and_subordinatessharing-rule recipient (configurable role-hierarchy widening), implemented in@objectstack/plugin-sharing(role-graph.tsRoleGraphService+sharing-rule-service.tsexpandRecipient) and covered by the plugin's own unit tests.While trying to demonstrate D6 in the showcase (as part of #2076), I found a deeper, pre-existing architectural gap that blocks it from being shown end-to-end.
The gap
Stack-declared
rolesandsharingRulesare never seeded intosys_role/sys_sharing_ruleat runtime — neither by the verify harness (bootStack) nor by the realpnpm devCLI (packages/cli/src/commands/serve.ts).Evidence:
bootStackyieldssys_rolecount = 0 andsys_sharing_rulecount = 0, even though the showcase declares 3 roles + 2 sharing rules.SharingServicePlugin.start()binds rule hooks fromruleService.listRules(), which reads thesys_sharing_ruletable — but nothing populates that table from app metadata. Boot logs show[sharing-rule] hooks bound {"objects":[],"ruleCount":0}.roles/sharingRulesintosys_role/sys_sharing_rule(only the runtimecreateRuleAPI atsharing-rule-service.ts:138writes the table).Consequence: the showcase's existing declarative roles + sharing rules (and any app's, e.g.
examples/app-crm) are decorative — Studio/authoring metadata that never enforces at runtime. This is a classic enforce-or-remove (ADR-0049) situation.Proposed work
Seed (idempotent upsert) stack-declared
roles→sys_roleandsharingRules→sys_sharing_ruleat boot, so the existing sharing-rule evaluator (rule-hooks.tsafterInsert/afterUpdate) activates them.SecurityPluginfor roles (sys_role),SharingServicePluginfor sharing rules (sys_sharing_rule), reading frommetadataService.list('role' / 'sharingRule').plugin-org-scoping).This changes enforcement behavior for every app that declares roles/sharing rules (
examples/app-showcaseandexamples/app-crmtoday). Activating previously-inert rules can change who-can-see-what. Requires:Acceptance criteria
sys_role/sys_sharing_ruleat boot (verify harness + CLI).role_and_subordinatessharing rule + a conventional role hierarchy (exec → manager → contributor), with an end-to-end dogfood proof that a manager + their subordinates gain access via the widening.References
packages/plugins/plugin-sharing/src/{role-graph,sharing-rule-service,rule-hooks,sharing-plugin}.ts,packages/cli/src/commands/serve.ts,packages/plugins/plugin-security/src/security-plugin.ts.