Skip to content

test+docs(dynamic): pin & document portable ruleset snapshots across environments (#76) - #82

Merged
2000game merged 1 commit into
mainfrom
feat/portable-ruleset-refs-76
Jul 10, 2026
Merged

2000game merged 1 commit into
mainfrom
feat/portable-ruleset-refs-76

Conversation

@2000game

Copy link
Copy Markdown
Member

Advances #76 (ruleset id portability) with the low-risk, unambiguous slice: pin and document the portability mechanism that already works, so the eventual adopt-time tooling has a tested, documented foundation. No engine change.

Background

The resolver already rewrites logical refs embedded anywhere inside a dynamic ruleset to the per-host id before diffing (collectRefs/deepMapRefs walk the whole folded fields bag in build.ts, incl. dynamic.ruleset), and the resolved form normalizes byte-faithfully against CT. That makes an inline churchQuery(...) ruleset portable across environments.

Two gaps:

  1. The property was only tested for the inline form. The { ref: "./rulesets/<key>.json" } snapshot-file path — exactly what ct adopt group --with-dynamic produces — was uncovered. A future refactor of the resolution/normalization pass could silently break cross-env rulesets.
  2. Nothing documented how to make a captured snapshot portable, or the interim cross-env caveat feat(dynamic): rulesets embed instance-specific numeric ids — not portable across environments #76 explicitly asks to surface ("documented, not silent").

Changes

Tests (tests/portable-refs.test.ts, +2) — over the FILE path, not just inline:

  • A {__ctRef} marker embedded in a ruleset JSON file resolves to each host's campus id in the PUT (dev 42 vs prod 7) from one identical config + file.
  • Once resolved, the ruleset diffs byte-faithfully — when CT already holds the resolved id, the group is a no-op (no re-PUT on every apply). This is the exact property a portable snapshot needs.

Docs (docs/dynamic-groups.md) — new "Portable snapshot files across environments (#76)" section:

  • Why captured snapshots embed instance-specific ids and break cross-env.
  • Two ways to make one portable: re-author with q/churchQuery/ref, or drop a { "__ctRef": true, "kind": "campus", "key": "mainz" } marker straight into the JSON file.
  • The numeric-passthrough escape hatch for operational groups outside the scaffold (mirrors bug(permissions): ct adopt grants assumes every scoped dataId is a group #49).
  • The interim "documented, not silent" cross-env caveat.

What this does NOT do (still open on #76)

The adopt-time auto-rewrite — ct adopt group --with-dynamic detecting managed-entity ids in captured query positions and emitting {__ctRef} markers automatically (with the var→ref-kind catalog, reverse-resolution against managed state, and passthrough+warning for unmanaged ids). That's the substantial design work #76 flags; the implementation plan is posted on the issue. This PR makes that work land on tested, documented ground.

Verification

  • npm run lint && npm run typecheck && npm test && npm run build — all green (535 tests, +2).

…environments (#76)

The resolver already rewrites logical refs anywhere inside a dynamic ruleset to
the per-host id before diffing (via collectRefs/deepMapRefs over the folded
fields bag), and the resolved form normalizes byte-faithfully against CT. That
made INLINE churchQuery rulesets portable, but the property was only tested for
the inline form — the { ref: "./file.json" } snapshot path (what adopt captures)
was uncovered, and nothing documented how to make a captured snapshot portable.

- tests: two regression tests over the FILE path — a {__ctRef} marker embedded in
  a ruleset JSON file resolves to each host's campus id in the PUT (dev 42 vs
  prod 7), and once resolved diffs byte-faithfully (a matching instance is a
  no-op, no re-PUT). Locks the resolution/normalization behaviour #76's tooling
  will build on so a future refactor can't silently regress it.
- docs: new 'Portable snapshot files across environments' section in
  docs/dynamic-groups.md — why captured snapshots embed instance-specific ids,
  the two ways to make one portable (re-author with q/churchQuery/ref, or drop a
  {__ctRef} marker into the JSON), the numeric-passthrough escape hatch for
  operational groups, and the interim 'documented, not silent' cross-env caveat.

No engine change: this pins and documents existing behaviour. The adopt-time
auto-rewrite of captured ids remains open on #76 (design posted there).
@2000game
2000game merged commit fb521c5 into main Jul 10, 2026
1 check passed
@2000game
2000game deleted the feat/portable-ruleset-refs-76 branch July 10, 2026 12:29
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.

1 participant