Skip to content

gcp: the provider-default prune entries the claimed-field set now covers #2184

Description

@lex00

#2172 (issue #2160) added the claimed-field set: packages/core/src/claimed-fields.ts derives, from a declaration's own props, every path it ever set. A live value on a path outside that set now reports correctly instead of being invisible or read as drift. (#2181 is renaming that #2172 bucket from "held elsewhere" to "unclaimed": DeepDiffResult.unclaimed, heading UNCLAIMED. Using "unclaimed" throughout this issue.)

#2172's PR body names the counterpart-gated provider-default entries in lexicons/gcp/src/deep-observe-hooks.ts as the largest shrink candidate for this lexicon, and says pruning and unclaimed report differently: pruned means the field never reaches the tree at all, unclaimed means it is reported with its live value under the UNCLAIMED heading. That is why shrinking one of these tables changes what a user sees on a clean estate, not just what chant computes internally. Nothing was shrunk in #2172 itself; this issue is the per-lexicon follow-up its acceptance line asked for.

What is in the file

gcpDeepNormalizationHooks.prune (lexicons/gcp/src/deep-observe-hooks.ts:156-184) checks two exported tables and two private pattern sets, in this order:

  • GCP_READ_ONLY_NAMES (lines 48-73): etag, selfLink, id, projectId, projectNumber, timeCreated, updated, createTime, updateTime, generation, metageneration, uid, uniqueId, email, state, reconciling, observedGeneration, uri, urls, conditions, terminalCondition, latestReadyRevision, latestCreatedRevision. Pruned on both sides regardless of what the declaration set (checked at line 159).
  • GCP_SERVICE_DEFAULTS (lines 87-114): StorageBucket (storageClass, locationType, publicAccessPrevention, uniformBucketLevelAccess, softDeletePolicy.retentionDurationSeconds), PubSubTopic (messageStoragePolicy.enforceInTransit), PubSubSubscription (ackDeadlineSeconds, expirationPolicy.ttl, enableMessageOrdering, enableExactlyOnceDelivery, retainAckedMessages, detached, retryPolicy.minimumBackoff), RunService (ingress, launchStage), IAMServiceAccount (disabled). 16 entries across 5 kinds. Only fires when node.side === "live" && node.counterpart === "absent" (the gate at line 172), which is exactly the shape the claimed-field set now answers without a hand-written value comparison.
  • CHANT_OWNERSHIP_LABEL_PATTERNS (lines 127-133): chant's own managed-by/stack/env label keys, pruned unconditionally (line 162).
  • CNRM_ENVELOPE_PATTERNS and CNRM_ANNOTATION_PREFIX (lines 136-137): CNRM machinery on the declared side that no REST payload ever echoes, pruned unconditionally on the declared side only (lines 166-167).
  • One inline rule with no exported name: an undeclared null or {} (GCP's own spelling of "unset") is pruned wherever it appears live and undeclared (lines 174-178).

Grepped every exported name across the lexicon and packages/core: none of these four is read anywhere but deep-observe-hooks.ts itself and deep-observe.test.ts. lexicons/gcp/src/export-resources.ts does not import them, so there is no second consumer to protect here.

Candidates versus must-stay

Candidate to shrink: GCP_SERVICE_DEFAULTS, all 16 entries. Each one only fires when the declaration never set the property, which claimedFieldsOfProps now answers directly. Removing an entry means a StorageBucket whose storageClass chant never declared reports storageClass: STANDARD under UNCLAIMED instead of nothing. The value was always true; it just was not visible before.

Must stay:

  • GCP_READ_ONLY_NAMES: server-assigned identity and bookkeeping, pruned on both sides, so a declared value would be meaningless to compare too. This is the read-only-name category feat(core): the claimed-field set, and a live value chant never set stops being drift #2172's body calls must-stay by name.
  • CHANT_OWNERSHIP_LABEL_PATTERNS: chant's own marker, not a provider default, unconditional rather than counterpart-gated.
  • CNRM_ENVELOPE_PATTERNS / CNRM_ANNOTATION_PREFIX: declared-side envelope pruning. The claimed-field set only classifies live values against the declaration, so it says nothing about this direction.

Cannot fully classify from the code alone: the inline null/{} rule (lines 174-178). It is not a per-kind value table; it fires on any undeclared live field regardless of kind. Removing it would report every genuinely-unset field as UNCLAIMED: null on every clean read across every kind, not just the five named above. That reads closer to must-stay than to the named defaults, but it needs the same real-estate check as the rest before anyone decides either way.

Verification before merging

Run chant lifecycle diff --live against a real GCP project covering at least one StorageBucket, one PubSubTopic, one PubSubSubscription, one RunService and one IAMServiceAccount, each declared with the relevant property left unset, before and after removing an entry. Confirm the field moves from invisible to UNCLAIMED with the correct live value, that a clean estate still reports zero drift, and that a declared value away from the default still reports as drift unchanged.

Ref #2160, #2172, #2181.

Acceptance

  • Each GCP_SERVICE_DEFAULTS entry removed has a test in lexicons/gcp/src/deep-observe.test.ts asserting the field now reports as unclaimed with its live value, not as drift and not invisible.
  • No entry moves without a matching real-estate run; the PR description names the project, the resource kinds and the fields checked.
  • No KNOWN_FAILURES entry added for any lexicon.
  • lexicons/gcp/src/deep-observe.test.ts passes in full.
  • GCP_READ_ONLY_NAMES, CHANT_OWNERSHIP_LABEL_PATTERNS and CNRM_ENVELOPE_PATTERNS/CNRM_ANNOTATION_PREFIX are untouched, or the PR explains why one of them turned out to be coverable after all.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions