RFC 972: Structured design context in synthesized templates - #981
RFC 972: Structured design context in synthesized templates#981satyakigh wants to merge 7 commits into
Conversation
| Context added on an outer scope cascades to all primary resources beneath it | ||
| with nearest-wins semantics: scalar fields (`why`, `mutable`, `trust`, `ops`) | ||
| from scopes closer to a resource override outer scopes, while list fields | ||
| (`must`, `gaps`, `deps`, `failureModes`) accumulate and de-duplicate. Like |
There was a problem hiding this comment.
Is this intended to propagate down the construct tree? For instance, in an L3 construct, would list fields accumulate on every resource within the construct?
A further question is - could this lead to biasing the user's AI agent? If they see a single string in a field repeated for each resource?
There was a problem hiding this comment.
Applying information to descendants is now explicit rather than automatic. The RFC also explains that repetition can make one fact appear disproportionately important and directs template-wide information to TemplateMetadataContext.
|
|
||
| Every resource context block records where it came from and how much to trust it. | ||
| When the caller omits `trust`, CDK emits `source: AUTHORED` and chooses confidence | ||
| from the declaration: `HIGH` when `why` or a non-empty `must` is present, otherwise |
There was a problem hiding this comment.
Could you give more clarity on when a user needs to be using a specific field. For instance, guidance in the README like
A human's preferred option should be .... On the other hand, an agent should be using .... by default.
One suggestion could be keeping AUTHORED primarily for humans, and INFERRED for agents to make it simpler.
There was a problem hiding this comment.
Added explicit guidance: people use AUTHORED for information they write or confirm. Automated producers use COMMENT, COMMIT, or INFERRED according to their evidence and must supply confidence explicitly.
iliapolo
left a comment
There was a problem hiding this comment.
@satyakigh Are you also looking for feedback on the schema itself, or just the CDK part of things?
|
|
||
| Add resource-level context on any construct scope. It is rendered onto the | ||
| scope's *primary* resources (the `defaultChild` chain of each construct), | ||
| skipping incidental helper resources like auto-created IAM policies: |
There was a problem hiding this comment.
What if the customer does want some context on these incidental resources? For example, a lambda.Function may implicitly create a dead letter queue. For completes, lets add an example of that:
MetadataContext.of(func).add(...); // primary resource context
MetadataContext.of(func.deadLetterQueue).add(...) // helper resources contextThis then begs the question of can we apply some default context. For example:
{
"Type": "AWS::SQS::Queue",
"Metadata:" : {
"com.aws.cloudformation.Context": {
"why": "Created by function MyFun to store failed invocation payloads",
"must": ["Size === 0"]
}
}
}Now the agent knows to see it as part of the same functionality vs just a floating resource. It would require a lot of code changes to aws-cdk-lib - if you agree it would be worth while, lets add it as a possible follow up / future enhancement.
There was a problem hiding this comment.
Mainly the CDK side of things, we can update the schema if required as well if you guys have suggestions
There was a problem hiding this comment.
Added examples for targeting an exposed helper directly, including a function's dead-letter queue. applyToAllResources supports intentionally including every helper. Selecting or populating helpers automatically by relationship remains future work.
| } | ||
| } | ||
| ``` | ||
|
|
There was a problem hiding this comment.
As a customer reading up to here I immediately wonder what keys are available and what they mean. Put a link to the schema appendix right here for quicker access (when we publish, the link should point to a proper page on the dev guide).
There was a problem hiding this comment.
Added an early link to Appendix A and the published CloudFormation Metadata Context schema. Appendix A and the CDK API docs mirror that schema; the CloudFormation authoring skill provides non-enforced guidance.
|
|
||
| Resource-level (`Resources.<LogicalId>.Metadata["com.aws.cloudformation.Context"]`): | ||
|
|
||
| | Field | Type | Meaning | |
There was a problem hiding this comment.
Add an Example column please (real life).
| | `must` | string[] | Hard invariants; violating any entry breaks something (data loss, outage, security, corruption, coupling). | | ||
| | `mutable` | enum | Resource-default change-safety: `must-never-change` \| `change-with-constraints` \| `review-required` \| `free-to-tune`. | | ||
| | `mutability` | map\<property, enum\> | Sparse per-property overrides; only properties deviating from the default or high-stakes. | | ||
| | `trust` | object | Provenance: `src` (`authored`\|`comment`\|`commit`\|`infer`), `conf` (`high`\|`medium`\|`low`), optional `cite`, `note`. | |
There was a problem hiding this comment.
Elaborate on the possible values of src, conf, cite, note (with examples).
There was a problem hiding this comment.
Added a dedicated trust-field table covering src, conf, cite, and note, including requiredness, allowed values, meanings, and examples.
| | `failureModes` | string[] | Failure/recovery paths (retries, timeouts, DLQs, circuit breakers). | | ||
|
|
||
| `authored` means explicitly declared through the API; it does not imply that a human was | ||
| the producer. A producer deriving context from comments, commits, or code structure must |
There was a problem hiding this comment.
it does not imply that a human was the producer
But if its an agent producing this context - isn't it always inferred from something? Give a concrete example of when each value here would be used?
There was a problem hiding this comment.
Clarified the source meanings with examples: authored is written or confirmed by a person, comment comes directly from a source comment, commit comes from version-control history, and infer is concluded from code or behavior.
| ``` | ||
|
|
||
| Every resource context block records where it came from and how much to trust it. | ||
| When the caller omits `trust`, CDK emits `source: AUTHORED` and chooses confidence |
There was a problem hiding this comment.
I assume that AUTHORED carries more trust than INFERRED? What prevents agents inferring context from using AUTHORED? or just not providing trust at all and then having CDK default to AUTHORED?
I think there needs to be a clearer definition and guidance. What is the main use-case for using AUTHORED? is it not human authored? if so - lets double down on that and provide agents with instructions to always use INFERRED when setting context.
There was a problem hiding this comment.
Removed the automatic AUTHORED default. trust is optional and may be used alone; when present, both source and confidence are required. AUTHORED means human-written or human-confirmed, though the API cannot prevent a caller from claiming it incorrectly.
| Resource-level (`Resources.<LogicalId>.Metadata["com.aws.cloudformation.Context"]`): | ||
|
|
||
| | Field | Type | Meaning | | ||
| |----------------|-----------------------|--------------------------------------------------------------------------------------------------------------------------| |
There was a problem hiding this comment.
Is everything optional here? add an Optionality column
There was a problem hiding this comment.
Added requiredness columns. All top-level Resource and Template Context fields are optional. When present, trust requires source and confidence, and an object-form ref requires at; CDK adds no other top-level requiredness.
|
|
||
| Every resource context block records where it came from and how much to trust it. | ||
| When the caller omits `trust`, CDK emits `source: AUTHORED` and chooses confidence | ||
| from the declaration: `HIGH` when `why` or a non-empty `must` is present, otherwise |
There was a problem hiding this comment.
So both why and must are optional? I don't think we should allow for context that doesn't specify why. Why are we trying confidence solely to the must field? I'd think a citation is more evidence for context than some invariants the agent may have inferred incorrectly. My proposal:
- HIGH: Both
mustandcitationare present. - MEDIUM: Only one is present.
- LOW: None are present.
There was a problem hiding this comment.
The published schema keeps why and must optional, so CDK does too. The RFC recommends why for significant resources and a must entry to explain constrained mutability, but does not enforce either. Confidence remains explicit whenever trust is supplied.
| ```ts | ||
| declare const stack: Stack; | ||
|
|
||
| MetadataContext.of(stack).addToTemplate({ |
There was a problem hiding this comment.
addToTemplate is an API thats going to be used far less than add - so lets not put them under the same object - to reduce cognitive load. Proposal:
TemplateMetadataContext.of(stack).add() // accets StackResourceMetadataContext.of(stack).add() // accepts Construct
This keeps things consistent. If construct vendors want to add template metadata (though they really shouldn't), they can use:
TemplateMetadataContext.of(Stack.of(construct)).add(...)There was a problem hiding this comment.
Split the API as proposed: ResourceMetadataContext.of(scope).add() handles resource information, and TemplateMetadataContext.of(stack).add() handles template information. MetadataContextMixin remains resource-only.
| `Metadata["com.aws.cloudformation.Context"]` is included in that measurement. This RFC adds no | ||
| context-specific size validator and never silently trims declared context. The | ||
| existing warning remains the synth-time signal; authoring tools may respond | ||
| using the advisory schema's tier/drop order described in appendix A. |
There was a problem hiding this comment.
How would agents know to consult this schema if cdk synth doesn't provide this guidance? we can at least print a link to the schema for the to follow.
There was a problem hiding this comment.
Added an early link to the published schema and documented the fields in the README and API reference. I did not add a notice to every cdk synth: it would be repetitive and unavailable to later GetTemplate readers. The stable metadata key and published documentation provide the durable reference.
| `must: ["VisTimeout >= 6x fn timeout, else dup on retry"]` in the template itself. | ||
| * **Operational handoff and incident response** - `why`, `ops` and `failureModes` carry | ||
| the on-call knowledge that normally lives in tribal memory: what the resource is for, | ||
| what to check before touching it, and what the failure/recovery paths are. |
There was a problem hiding this comment.
What do you mean by failure/recovery paths? For example if failure mode is retry 3x w/ exp backoff before DLQ - what is the agent expected to do? look at the DLQ?
There was a problem hiding this comment.
Removed failureModes because it is not in the published schema. Failure behavior that must be preserved belongs in must, design reasoning belongs in why, and external operational procedures can be linked through template-level ref.
| modifies your stack six months from now often has the template and the live stack - not | ||
| your source repository, your design doc, or you. | ||
|
|
||
| Concrete situations this feature addresses: |
There was a problem hiding this comment.
This answers why the context is needed, not why it should be provided as a concrete API in the CDK.
I'd expect also something like "CDK customers will have a hard time defining the correct context without this feature" (because escape hatches suck).
Also needs to touch on the cascading mechanism you're proposing.
There was a problem hiding this comment.
Added a dedicated explanation. Low-level metadata methods provide no typed fields, allowed-value checks, required trust checks, primary-resource selection, descendant selection, merge behavior, or generated documentation across CDK languages. The dedicated APIs provide those behaviors.
| keeping heuristic inference and its review outside the core API contract. | ||
|
|
||
| If you already maintain design context in READMEs or wikis, this feature does not replace | ||
| them - it puts the *operationally relevant* subset where every consumer of the deployed |
There was a problem hiding this comment.
But this also creates duplication. I'm wondering why not use ref as a way to also point to the artifacts in the repo (design doc/runbook). Why would ref be suitable for org-wide rules but not for the repository URL for example?
There was a problem hiding this comment.
Updated ref to match the published schema: references may use relative paths, s3://, or https://. CDK does not fetch or restrict those locations. Referenced content is untrusted, and inline template context remains authoritative.
|
|
||
| * **Stale context is worse than no context.** Rationale written once and never updated | ||
| actively misleads the consumers it was meant to help. Co-location in reviewed CDK source | ||
| and the `trust`/`gaps` fields reduce the risk but do not remove it. |
There was a problem hiding this comment.
How do trust / gaps reduce the risk?
There was a problem hiding this comment.
Removed gaps, which is not in the published schema. trust communicates provenance and confidence; it does not prevent drift. Keeping context beside reviewed CDK code helps readers assess it, but does not guarantee that it stays current.
| `must`. Explicit trust values always win. | ||
|
|
||
| Change-safety uses a closed four-level enum: `must-never-change`, | ||
| `change-with-constraints`, `review-required`, `free-to-tune`. In the CDK API this is the |
There was a problem hiding this comment.
What does change-with-constraints mean exactly? the other ones are pretty sefl explanatory.
There was a problem hiding this comment.
Defined change-with-constraints as allowing change only while the stated rules remain true. The RFC recommends documenting those rules in must, but the published schema and CDK do not require it.
| * Sibling metadata namespaces remain untouched, and Context has no deployment-behavior | ||
| effect because CloudFormation ignores advisory metadata. | ||
|
|
||
| ### What alternative solutions did you consider? |
There was a problem hiding this comment.
What about having the context just be a bunch refs in the that point to source code, design docs, runbooks, etc for agents to follow? This prevents the risk of drift.
There was a problem hiding this comment.
Documented the trade-off: ref entries can point to relative paths, s3://, or https:// and reduce duplication or drift. They supplement rather than replace irreducible inline context, so an unavailable reference does not block safe use.
| confident-sounding context. The `trust` field exists precisely so generated context can | ||
| self-identify (`src: infer`, low confidence, citation) — but the API cannot force | ||
| honesty, and a caller is free to claim `authored`. | ||
| * **Merge-semantics complexity.** Nearest-wins plus accumulate-and-dedupe is more to |
There was a problem hiding this comment.
Its not just about learning curve - its about wether the customer actually wants the cascading effect. I can see scenarios where context is being added to an L3 with a very specific construct in mind, but then having in travel to a bunch of other resources as well might create unexpected results.
I'd say there is a risk of out-of-place context being added. This won't happen with pure CFN because the customer has no choice but to explicitly add the right context to each resource they want.
To evaluate this risk I think we need more examples of L3s
There was a problem hiding this comment.
Addressed this by making descendant selection explicit. The default selects only a CfnResource or a construct's defaultChild resource. applyToDescendants, applyToAllResources, and resource-type filters must be requested explicitly, and a declaration selecting zero resources is defined to fail.
| [aws/aws-cdk#38381](https://github.com/aws/aws-cdk/pull/38381). | ||
|
|
||
| The feature ships under the standard core review bar: it is small, opt-in, and has no | ||
| feature-flag interaction. Nothing about it needs to bake behind an experimental gate: |
There was a problem hiding this comment.
Why not have a bake period though? it could help hone the corresponding skill so we don't have to break the schema often.
There was a problem hiding this comment.
Added concrete stability requirements: review the public documentation, test the authoring and reading tools on real stacks, and obtain API Bar Raiser approval. A runtime feature flag is unnecessary because applications produce no additional Context unless they call the new APIs.
| feature-flag interaction. Nothing about it needs to bake behind an experimental gate: | ||
| the feature emits nothing until its APIs are adopted, so existing output remains unchanged. | ||
|
|
||
| ### Are there any open issues that need to be addressed later? |
There was a problem hiding this comment.
These are future enhancements really more than open issues. Is there anything we still need to discuss to move along with the implementation - is the spirit of this question.
There was a problem hiding this comment.
Split the section into requirements before declaring the API stable and separate future enhancements. The future list now covers automatic dependency discovery, automatic change-safety guidance, helper-resource selection, and properties on higher-level constructs.
| externalization `ref` are never dropped). CDK warns on the whole serialized template but | ||
| does not automatically apply this drop order. | ||
|
|
||
| ### Appendix B - Benchmark and implementation evidence |
There was a problem hiding this comment.
Can you share the actual data as well?
There was a problem hiding this comment.
Added the data and methodology: 33 tasks, three runs per condition. Scores were 65.20% without added information, 93.56% with template comments, 94.70% with structured metadata but no special instructions, and 98.63% with structured metadata plus instructions. The RFC also documents the scoring and task-selection limitations.
This is a request for comments about Structured design context in synthesized templates. See #972 for
additional details.
APIs are signed off by @iliapolo
By submitting this pull request, I confirm that my contribution is made under
the terms of the Apache-2.0 license