Skip to content

feat(core): embed structured design context in synthesized templates (MetadataContext) - #38381

Open
satyakigh wants to merge 19 commits into
aws:mainfrom
satyakigh:context-constructs
Open

satyakigh wants to merge 19 commits into
aws:mainfrom
satyakigh:context-constructs

Conversation

@satyakigh

@satyakigh satyakigh commented Jul 22, 2026 •

Copy link
Copy Markdown
Contributor

Issue # (if applicable)

RFC tracking issue: aws/aws-cdk-rfcs#994

Accepted RFC: aws/aws-cdk-rfcs#981

Reason for this change

CloudFormation templates preserve deployed configuration but usually lose the rationale, invariants, change-safety guidance, and provenance available in CDK source. CloudFormation defines the advisory com.aws.cloudformation.Context metadata schema for preserving that information, but CDK users need a typed authoring API.

Description of changes

  • Adds CfnResourceMetadataContext for setting or clearing Context on selected CfnResource constructs during synthesis.
  • Adds CfnTemplateMetadataContext for setting or clearing template-level Context.
  • Mirrors the published resource, template, mutability, reference, and trust fields without adding another vocabulary.
  • Uses IConstructSelector for explicit resource targeting. The default selects a CfnResource scope or its immediate CfnResource default child.
  • Uses complete-value replacement rather than implicit merging. Aspect priority and scope determine which overlapping operation applies last.
  • Preserves NestedStack behavior and does not cross Stage assembly boundaries.
  • Rejects invalid trust data, redundant sparse mutability entries, selectors that match no CfnResource, and unresolved values in top-level template Context.
  • Adds public API documentation, README examples, unit coverage, and an integration snapshot.

The public API and stable-release plan were approved in RFC 994. The approved surface keeps resource Context separate from targeting options. jsii generates Python as set(context, *, priority=None, selector=None) and Java as set(context) or set(context, options). RFC 994 also requires rejecting a mutability entry that repeats the resource-level mutable default so the map remains sparse. Existing applications synthesize unchanged unless they call the new APIs.

Checklist


By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license

@satyakigh
satyakigh requested a review from a team as a code owner July 22, 2026 23:46
@github-actions github-actions Bot added p2 beginning-contributor [Pilot] contributed between 0-2 PRs to the CDK labels Jul 22, 2026
@aws-cdk-automation
aws-cdk-automation requested a review from a team July 22, 2026 23:47

@aws-cdk-automation aws-cdk-automation left a comment •

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(This review is outdated)

@satyakigh satyakigh changed the title feat(core): Add MetadataContext for structured template context feat(core): add MetadataContext for structured template context Jul 22, 2026
@aws-cdk-automation
aws-cdk-automation dismissed their stale review July 22, 2026 23:51

✅ Updated pull request passes all PRLinter validations. Dismissing previous PRLinter review.

@satyakigh
satyakigh force-pushed the context-constructs branch from 8da308b to 517cab1 Compare July 22, 2026 23:51

@mrgrain mrgrain left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey, since the feature is already stable, the Mixin should go straight into aws-cdk-lib as well. The preview package is being phased out.

@mergify
mergify Bot dismissed mrgrain’s stale review July 23, 2026 04:10

Pull request has been modified.

@aws-cdk-automation aws-cdk-automation added the pr/needs-community-review This PR needs a review from a Trusted Community Member or Core Team Member. label Jul 23, 2026
@satyakigh
satyakigh force-pushed the context-constructs branch from b362a0a to b6106b6 Compare July 23, 2026 14:28
@satyakigh

Copy link
Copy Markdown
Contributor Author

Hey, since the feature is already stable, the Mixin should go straight into aws-cdk-lib as well. The preview package is being phased out.

Sounds good, updated

@satyakigh
satyakigh force-pushed the context-constructs branch from b6106b6 to 5caa8fa Compare July 26, 2026 19:47

@maintainer-for-aws maintainer-for-aws Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See the review summary comment for the overview; the notes below are inline.

…and aspect + mixins to set context on a resource and template
…ib core

The mixins-preview package is being phased out and the feature is stable,
so the Mixin ships directly in aws-cdk-lib alongside the MetadataContext
facade (review feedback).

- MetadataContextMixin now lives in core/lib/mixins/ and is exported flat
  from aws-cdk-lib (a top-level 'mixins' jsii submodule is not possible:
  JSII5011 name conflict with the Mixins class), with an awslint exclusion
  for the mixin-namespace rule.
- Unit test moved to core/test/mixins/, adapted to core's toCloudFormation
  convention.
- Integ test moved to @aws-cdk-testing/framework-integ test/core/test/
  with regenerated snapshot.
- aws-cdk-lib README documents the mixin inline; all mixins-preview
  changes reverted.

@maintainer-for-aws maintainer-for-aws Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See the review summary comment for the overview; the notes below are inline.

Comment thread packages/aws-cdk-lib/core/lib/stack.ts Resolved

@maintainer-for-aws maintainer-for-aws Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See the review summary comment for the overview; the notes below are inline.

@iliapolo iliapolo left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@satyakigh the implementation is not aligned with the latest RFC (contains context merging which we decided to drop). Let me know when to review this

@maintainer-for-aws maintainer-for-aws Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See the review summary comment for the overview; the notes below are inline.

@maintainer-for-aws maintainer-for-aws Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See the review summary comment for the overview; the notes below are inline.

* The selector runs during synthesis, so it also covers resources added
* beneath the scope after this call. This method never throws; invalid
* values and a call that selects no `CfnResource` fail synthesis.
*/

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔴 Blocking — CfnResourceMetadataContext.set(context, options) takes a struct (CfnResourceContextProps) as its first parameter followed by a second struct (CfnResourceMetadataContextOptions). jsii models a struct as the trailing options object and expands it into keyword/named arguments in Python, Java, C#, and Go; a struct that is not the last positional parameter cannot be represented that way, so any parameter after a struct breaks the generated bindings even though TypeScript accepts it (jsii structs). This is a jsii-exported public method in the most foundational package, so the signature is effectively permanent once released. It also diverges from the sibling pattern (RemovalPolicies.of(scope).apply(policy, props?), Tags.of(x).add(key, value, props?)), which keeps the single struct last.

Suggested change: Keep exactly one trailing struct: either fold the targeting fields (selector, priority) into CfnResourceContextProps so set(context) takes a single struct, or restructure so the only struct is the last parameter and any leading parameter is a non-struct.

Comment on lines +98 to +106
}

function validateMutability(context: CfnResourceContextProps): string[] {
if (context.mutable === undefined || context.mutability === undefined) {
return [];
}
return Object.entries(context.mutability)
.filter(([, level]) => level === context.mutable)
.map(([property]) => `MetadataContext mutability entry '${property}' must not repeat mutable ${JSON.stringify(context.mutable)}; the map records deviations only`);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Recommended — validateMutability fails synthesis whenever a mutability entry repeats the mutable default and both are supplied in the same set() call. An entry such as set({ mutable: FREE_TO_TUNE, mutability: { QueueName: FREE_TO_TUNE } }) is not contradictory — it names the same safety level the resource already defaults to, a harmless no-op — yet it hard-fails cdk synth. The underlying CloudFormation Metadata Context schema only recommends listing deviations, placing no such exclusion constraint on the map, so erroring here is stricter than the advisory vocabulary and surprises users with a build break over an input that causes no harm (AGENTS.md#error-handling).

Suggested change: In renderResourceContext, drop the redundant entries instead of failing: filter the rendered mutability map to entries whose level differs from context.mutable, yielding the schema-preferred sparse map, and remove (or downgrade to a warning) the corresponding error in validateMutability.

@maintainer-for-aws maintainer-for-aws Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See the review summary comment for the overview; the notes below are inline.

* CloudFormation Metadata is visible through service APIs. Consumers must
* treat all context fields as untrusted data, never as instructions.
*/
export interface CfnResourceContextProps {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚪ Optional — The content props interfaces CfnResourceContextProps (line 206) and CfnTemplateContextProps (line 298) drop the "Metadata" segment from their class names (CfnResourceMetadataContext, CfnTemplateMetadataContext), while the sibling options interface CfnResourceMetadataContextOptions in the same file does derive from the full class name. Related types should derive from the class name so one family follows one convention (AGENTS_CONSTRUCT_DESIGN.md#resource--type-naming). Because this is a stable aws-cdk-lib/core surface, the names lock in on release, so a permanent inconsistency is cheap to avoid now.

Suggested change: Rename CfnResourceContextProps → CfnResourceMetadataContextProps and CfnTemplateContextProps → CfnTemplateMetadataContextProps so all related types derive from the class name consistently (or, if the shorter stems are preferred, rename the options interface to match them).

@github-actions

github-actions Bot commented Nov 2, 2026

Copy link
Copy Markdown
Contributor

👋 It looks like your PR description follows the template but is missing a valid issue number in the first section.

PRs without a linked issue will receive lower priority for review and merging. Please update the description to include a reference like Closes #123. If no existing issue matches your change, create one first.

@maintainer-for-aws maintainer-for-aws Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See the review summary comment for the overview; the notes below are inline.

Comment on lines +19 to +28
}
if (context.mutability !== undefined) {
if (Token.isUnresolved(context.mutability)) {
out.mutability = context.mutability;
} else {
const entries = Object.entries(context.mutability);
const deviations = entries.filter(([, level]) => level !== context.mutable);
if (entries.length === 0 || deviations.length > 0) {
out.mutability = Object.fromEntries(deviations);
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Recommended — renderResourceContext has a dedicated branch for an unresolved mutability map that passes the token through verbatim and short-circuits the entries/deviations filtering, because iterating a token map with Object.entries() would be wrong. The unit suite exercises token/Lazy inputs only for the list fields (must, deps), never for mutability, so this is the one branch of renderResourceContext with no asserting test. If the guard regressed — falling through to Object.entries() on the token and throwing, or silently dropping the map — the suite would stay green. A Token.isUnresolved guard owes a test that passes an unresolved token through it (AGENTS.md#unit-tests).

Suggested change: Add a resource-level test alongside the existing Lazy test that sets mutability to an unresolved token (e.g. Lazy.any({ produce: () => ({ QueueName: 'must-never-change' }) })) and asserts the rendered Metadata contains the resolved map unchanged (including an entry that would otherwise be filtered as redundant), locking in that the token is passed through without the sparse-deviation filtering.

This branch was previously deployed

1 inactive deployment
automation — 127422b9 Deployed Nov 3, 2026 by satyakigh via validate-pr #376413
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

beginning-contributor [Pilot] contributed between 0-2 PRs to the CDK p2 pr/community-review-timeout pr/needs-maintainer-review This PR needs a review from a Core Team Member

Projects

None yet

Development

Successfully merging this pull request may close these issues.

7 participants