GraphQL: meaning of unmergedChangesCount = null and stable verification of pending changes
bryanbonmarchand
HOBBYOP

a day ago

Hello,

We are seeking clarification of the read-only contract before making any deployment decision.

Our reads show:

  • environment(id: ...).unmergedChangesCount is null, with no GraphQL error.
  • environmentStagedChanges(environmentId: ...).patch(decryptVariables: false) returns {}.
  • EnvironmentPatch.id remains stable, but EnvironmentPatch.createdAt and EnvironmentPatch.updatedAt change between requests and appear to correspond to the time of the read.
  • environment(id: ...).configEtag remains stable.
  • The returned identifier does not appear in the fully paginated history. Resolving it through environmentPatch(id: ...) fails; the EnvironmentPatch.environment relation also returns a generic error.

Could you clarify:

  1. What exactly does environment.unmergedChangesCount count, and what does null mean?
  2. Can environmentStagedChanges return a synthetic, non-persisted object with regenerated timestamps? How can it be distinguished from an actual patch?
  3. Is an empty patch(decryptVariables: false) together with a stable environment.configEtag sufficient to establish the absence of changes, including changes involving variables? If not, what complete, atomic or versioned read should be used in the presence of concurrent modifications?
  4. Among EnvironmentPatch.id, status, createdAt, updatedAt and environment.configEtag, which fields are authoritative when comparing two reads?

Our verifier remains blocked: we treat neither null as zero, nor an empty patch or timestamps as sufficient proof. We are requesting technical clarification only, with no changes, deployment, restart or subscription change.

Awaiting Railway Response

2 Replies

Railway
BOT

a day ago

When an environment has no stored staged patch, environmentStagedChanges is non-nullable, so it returns a synthetic EnvironmentPatch built at request time. That object is not persisted. It has status: STAGED, appliedAt: null and empty contents. Because it is never stored, it does not appear in environmentPatches and cannot be resolved through environmentPatch(id:). You can tell it apart from a real patch by its id: the synthetic object carries the literal placeholder <empty>, while a real record always has a UUID. A real staged record, including one emptied by Discard, does appear in environmentPatches and keeps its original createdAt.

To check for pending changes, read the change count from the patch contents. The public EnvironmentPatch type has no count field, so an empty patch(decryptVariables: false) is the authoritative signal. The dashboard uses this same signal to decide whether to show the staged-changes bar. The contents cover service instance fields (including create and delete flags), volumes, buckets, groups, shared variables (including unsets) and the private-networking toggle, so an empty patch also means no variable changes are staged. status, appliedAt, timestamps and whether a record exists do not establish anything on their own.

We can't confirm from here what unmergedChangesCount returning null means, or exactly what configEtag versions. Don't treat either one as evidence that nothing is staged. Gate on the empty patch contents.


Status changed to Awaiting User Response Railway • 1 day ago


bryanbonmarchand
HOBBYOP

2 hours ago

Thank you. We are evaluating the official IaC saved-plan workflow as an alternative to staged patch commits. Before relying on it for a protected deployment, could a human maintainer confirm:

  1. Does Environment.configEtag change for every pending staged edit, including sealed-variable updates and unsets, or only for applied IaC configuration? Are Environment.config(decryptVariables: false) and configEtag read from one consistent snapshot?
  2. When environmentApplyChangeSet receives baseConfigEtag, can it apply or merge pre-existing staged changes outside the reviewed changeSet? What supported workflow guarantees that only the saved, reviewed changes are applied and rejects any concurrent staged edit?
  3. What supported mechanism binds that reviewed configuration to the exact application commit or immutable image digest actually deployed, and rejects a changed code artifact? Does the same optimistic-concurrency guarantee cover deployment, or only configuration application?

We have read the saved-plan documentation and CLI v5.49.6 implementation. We are not treating unmergedChangesCount: null or changing synthetic patch timestamps as proof of no pending changes.


Status changed to Awaiting Railway Response Railway • about 2 hours ago


Welcome!

Sign in to your Railway account to join the conversation.

Loading...