fix(permissions)!: address group_type_role by role, not by group type (#182) - #187
Merged
Merged
Conversation
…#182) `/permissions/group_type_role/<id>` is keyed by the ROLE id. `ct.groupTypeRole({ groupType })` resolved the group TYPE id and used it as the domain, so it silently addressed whichever role shared that number. On eqrm prod the Struktur type (9) landed on Group/Leiter (role 9); on dev it addressed no role at all, and two empty declarations there would strip the Struktur-leader and Merkmal-Leiter roles on the next apply. `ct.groupTypeRole` now takes `groupType` + `role` and resolves the pair against `/group/roles` through the existing `ref.groupTypeRole` resolver. A bare `groupType` is an eval-time error: ChurchTools has no type-wide grant set to fall back to. BREAKING CHANGE: `ct.groupTypeRole({ groupType })` without `role` no longer loads. Declare one block per role, e.g. `ct.groupTypeRole({ key, groupType: "struktur", role: "Mitglied", grants })`. A same-run-created group type can no longer be a pending group_type_role domain, since its roles do not exist before it does.
… in the planner too Address review of #187: the DSL guard alone left resolveDomainIds willing to resolve a group-type Ref to the type id. The #69 tests that asserted that mis-addressed PUT now assert the refusal and the same-run limitation (#189). Correct the docs that still described group-type pending domains, name each domain's portable form in adopt output, keep instance specifics out of comments, and re-sign the handbook pages.
# Conflicts: # docs/runbook-manual-surface.md
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #182.
What was wrong
/permissions/group_type_role/<id>is keyed by role id.ct.groupTypeRole({ groupType })resolved the group type id and used that as the domain, so it addressed whichever role happened to share the number.Read live on 2026-09-26 (
/group/rolesagainst.ct/ids.<host>.jsonin eqrm/ct-structure):struktur_roles(33 grants)flow_roles(8)newsletter_roles(15)connectgruppe_roles(16)commitment_roles(declared empty)community_roles_emptyProd has not been mis-written, because every set was adopted from live and round-trips. Dev is the risk: the two empty declarations own real roles there, so the next
ct apply --env devwould revoke their grants.The change
ct.groupTypeRoletakesgroupType+role. The pair resolves through the existingref.groupTypeRoleresolver (slug match within the type, ambiguity error,/group/rolescatalog).groupTypeis an eval-time error that points at group_type_role resolves a group TYPE id where the API expects a ROLE id —struktur_rolesmanages Group-Leiter #182. There is no type-wide grant set in ChurchTools to default to.ct adopt grants group_type_role <id>now says in its comment that the id is a role id and names the portable form.handbuch/permissions.md(domainId semantics, examples, the same-run note),ci.md,runbook-manual-surface.md.Breaking: this ships as v4.0.0. eqrm/ct-structure pins
^3.10.1and moves to v4 in the same PR that rewrites its 13 declarations per role.Not in this PR
ct report permissionsundercounting type-level roles (eqrm/ct-structure#107). That is a separate path insrc/reports/./dbfields, group-type change, README). They go in their own docs PR.Verification
vitest: 1196 passed. The tests that encoded the old reading now assert the role id, using a fixture where the type id and a foreign role id collide on purpose.tsc --noEmit,eslint,prettier --checkare clean.Review (2026-09-26)
A
/code-review highpass found 10 things. The code-level ones were checked with a throwaway plan test against this head, not only by reading.Fixed here (88f940b):
struktur_rolesmanages Group-Leiter #182 bug through.resolveDomainIdsresolved agroup-typeRef for agroup_type_roledomain to the type id, andtests/permission-pending-domain.test.tsasserted exactly thatPUT /permissions/group_type_role/<type id>. The planner now refuses it. The bug(permissions): domain-by-reference to a not-yet-created group type aborts the entire plan — fresh-instance rehearsal impossible #69 tests became a regression test (fails before, passes after), a test for the same-run limitation, and a typo test.handbuch/permissions.md, theci.mdpending-domain bullet and theapply.tscomment still described group-type pending domains. They now name the real ones: person status (feat(permissions): manage the person-status grant domain (ct.status) #90) andgroup_role(bug(permissions): group + its own groupRole in one config can never plan on a fresh host (the domain half of #29) #106).ct adopt grants status <id>said "adopt the group…". Each domain type now names its own portable form, with a test.blueprints.mdsnippet now usesgroupType+role, matchingexamples/campus-blueprint.config.ts. The three stale handbook pages are re-read and re-signed.Follow-up, #189: a same-run group type or role definition makes
ct planfail instead of going pending (confirmed). The old one-run path was never correct: it wrote to the type id. Also in #189: the ambiguity error'srole-defadvice can't be expressed inct.groupTypeRole, and adopt could print the portable form directly.main (#188) merged in; the runbook row conflict was resolved to keep both edits. 1195 tests, tsc, eslint, prettier, docs-staleness: all clean locally.