Skip to content

fix(permissions)!: address group_type_role by role, not by group type (#182) - #187

Merged
2000game merged 3 commits into
mainfrom
fix/182-group-type-role-by-role
Sep 26, 2026
Merged

2000game merged 3 commits into
mainfrom
fix/182-group-type-role-by-role

Conversation

@2000game

@2000game 2000game commented Sep 26, 2026 •

Copy link
Copy Markdown
Member

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/roles against .ct/ids.<host>.json in eqrm/ct-structure):

Declaration in ct-structure prod hits dev hits
struktur_roles (33 grants) Group / Leiter no role
flow_roles (8) Group / Mitglied no role
newsletter_roles (15) Team / Mitglied no role
connectgruppe_roles (16) Team / Leiter no role
commitment_roles (declared empty) no role Struktur / leader
community_roles_empty no role Merkmal / Leiter

Prod 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 dev would revoke their grants.

The change

  • ct.groupTypeRole takes groupType + role. The pair resolves through the existing ref.groupTypeRole resolver (slug match within the type, ambiguity error, /group/roles catalog).
  • A bare groupType is an eval-time error that points at group_type_role resolves a group TYPE id where the API expects a ROLE id — struktur_roles manages 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.
  • Docs: 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.1 and moves to v4 in the same PR that rewrites its 13 declarations per role.

Not in this PR

  • ct report permissions undercounting type-level roles (eqrm/ct-structure#107). That is a separate path in src/reports/.
  • The other known doc errors (group-status catalog, /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 --check are clean.

Review (2026-09-26)

A /code-review high pass found 10 things. The code-level ones were checked with a throwaway plan test against this head, not only by reading.

Fixed here (88f940b):

Follow-up, #189: a same-run group type or role definition makes ct plan fail 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's role-def advice can't be expressed in ct.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.

…#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
@2000game
2000game merged commit 02b7186 into main Sep 26, 2026
3 checks passed
@2000game
2000game deleted the fix/182-group-type-role-by-role branch September 26, 2026 12:18
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

group_type_role resolves a group TYPE id where the API expects a ROLE id — struktur_roles manages Group-Leiter

1 participant