Summary
ct plan hard-errors when a config declares a right that is not in the active permission catalog. For an estate whose instances genuinely have different modules installed, that makes a single host-portable config impossible — the config can be valid on one host and fatal on another, with no way to express the difference.
Request: downgrade this to a skip-with-warning, matching how ct already treats the mirror case.
The asymmetry
ct already handles the other direction gracefully. A live grant whose authId is absent from the catalog is reported and left alone:
! group_role #1920 ("implementierung_churchtools_mitglied"): a live grant carries
authId 2066, which is not in the permission catalog — left untouched (never
revoked). Capture this instance's own catalog (`ct permissions catalog --refresh`)
if this right should be manageable.
That is the right posture: say what you cannot manage, manage the rest. But the reverse — a declared right the catalog does not define — aborts the whole plan:
✗ ct.config.ts:2338 — group_role "implementierung_churchtools_mitglied":
"preserveUnknown" names a scope dimension no right in the permission catalog
scopes by: crp_query. A dimension that matches nothing would preserve nothing and
read exactly like "there was nothing to preserve" — check the spelling against
`ct get permissions-catalog`.
One declaration that does not apply to this host takes down planning for everything that does.
How we hit it
eqrm/ct-structure is one config applied to two instances. Dev had no per-instance capture, so it silently resolved every right through ct-cli's bundled catalog — a snapshot taken from prod. Under that borrowed catalog, prod-only rights resolved fine on dev and the config looked portable.
Capturing dev's own catalog made it truthful, and the config stopped planning there. 13 of the 113 declared rights do not exist on dev:
| Rights |
Why dev lacks them |
jpmFlowManager:* (10) |
Flow is not installed on dev |
churchreport:view, churchreport:view query |
Report module is not installed on dev |
churchreport:edit masterdata |
deleted by ChurchTools in 3.136.2 — a genuine config bug, fixed separately |
The first 12 are not errors. They are correct on prod and inapplicable on dev.
Note the trap: the config was never portable, but nothing could tell us, because the missing capture masked it. Capturing the catalog — which ct itself prescribes — is what surfaced the breakage.
Why not the obvious workarounds
- Environment conditionals in the config. Defeats the point of one declarative file, and this repo deliberately has none.
- Drop the module rights. Surrenders management of rights that are live and correct on prod.
- Install the modules on dev. Best fidelity, but licensing and instance changes are not always available, and
ct should not require two instances to be identical to plan against both.
Proposed behaviour
When a declared right, or a preserveUnknown dimension, is absent from the active catalog:
- emit a warning naming the right, the
group_role, and the host's catalog version
- skip that grant for this host, never planning it as a grant or a revoke
- keep planning everything else
- keep
--detailed-exitcode semantics unchanged (a skip is not a pending change)
Reserve the hard error for the case it was written for: a right absent from every catalog ct knows, which is a typo or a deleted right rather than a host difference. A flag (--strict-catalog) could restore today's behaviour for anyone who wants planning to fail on any unresolvable declaration.
Environment
- ct-cli 3.6.x (bundled catalog: ChurchTools 3.134.0, 187 rights)
- prod
eqrm.church.tools — ChurchTools 3.136.2, 187 rights
- dev
eqrm-dev.church.tools — ChurchTools 3.137.0-RC13, 221 rights
Related: 18 authIds in the 2050–2078 range denote different rights on the two hosts, since CT allocates custom-module ids per instance in install order. Declaring by string key keeps that safe today, and this request does not change it — but it is the reason per-instance captures must be adopted, which is what exposed this bug.
Summary
ct planhard-errors when a config declares a right that is not in the active permission catalog. For an estate whose instances genuinely have different modules installed, that makes a single host-portable config impossible — the config can be valid on one host and fatal on another, with no way to express the difference.Request: downgrade this to a skip-with-warning, matching how
ctalready treats the mirror case.The asymmetry
ctalready handles the other direction gracefully. A live grant whose authId is absent from the catalog is reported and left alone:That is the right posture: say what you cannot manage, manage the rest. But the reverse — a declared right the catalog does not define — aborts the whole plan:
One declaration that does not apply to this host takes down planning for everything that does.
How we hit it
eqrm/ct-structureis one config applied to two instances. Dev had no per-instance capture, so it silently resolved every right through ct-cli's bundled catalog — a snapshot taken from prod. Under that borrowed catalog, prod-only rights resolved fine on dev and the config looked portable.Capturing dev's own catalog made it truthful, and the config stopped planning there. 13 of the 113 declared rights do not exist on dev:
jpmFlowManager:*(10)churchreport:view,churchreport:view querychurchreport:edit masterdataThe first 12 are not errors. They are correct on prod and inapplicable on dev.
Note the trap: the config was never portable, but nothing could tell us, because the missing capture masked it. Capturing the catalog — which
ctitself prescribes — is what surfaced the breakage.Why not the obvious workarounds
ctshould not require two instances to be identical to plan against both.Proposed behaviour
When a declared right, or a
preserveUnknowndimension, is absent from the active catalog:group_role, and the host's catalog version--detailed-exitcodesemantics unchanged (a skip is not a pending change)Reserve the hard error for the case it was written for: a right absent from every catalog
ctknows, which is a typo or a deleted right rather than a host difference. A flag (--strict-catalog) could restore today's behaviour for anyone who wants planning to fail on any unresolvable declaration.Environment
eqrm.church.tools— ChurchTools 3.136.2, 187 rightseqrm-dev.church.tools— ChurchTools 3.137.0-RC13, 221 rightsRelated: 18 authIds in the 2050–2078 range denote different rights on the two hosts, since CT allocates custom-module ids per instance in install order. Declaring by string key keeps that safe today, and this request does not change it — but it is the reason per-instance captures must be adopted, which is what exposed this bug.