.agents/skills/review-schema/SKILL.md
Assume the @maintainer persona. Scope: model struct, attributes, blocks, validators, plan modifiers, timeouts on non-test resource code. Loaded from review-pr.
type fooResourceModel struct {
framework.WithRegionModel // first field; omit for global services only
// attributes...
Timeouts timeouts.Value `tfsdk:"timeouts"` // only when a timeouts block is present
}
framework.WithRegionModel is the first embedded field for regional resources/data sources/list resources. Global services (CloudFront, IAM, Route 53 hosted zones, etc.) omit it and register with inttypes.ResourceRegionDisabled().tfsdk tags must match schema attribute names exactly (snake_case).types.String, etc.) and fwtypes.ListNestedObjectValueOf[T] for nested blocks.timetypes.RFC3339, never types.String.snake_case.Attributes and within Blocks. No blank lines between attributes.internal/names constants (names.AttrARN, names.AttrName, names.AttrTags, names.AttrTagsAll, names.AttrTimeouts, etc.) instead of string literals when one exists.Only four valid combinations. Flag any other.
| Required | Optional | Computed | When |
|---|---|---|---|
| ✓ | User must supply | ||
| ✓ | User may supply; never use Default here | ||
| ✓ | Read-only | ||
| ✓ | ✓ | User or provider supplies; required pairing for Default |
Prefer Optional + Computed over Optional + Default when AWS supplies a server-side default.
id attributePlugin Framework does not require an id attribute. Include names.AttrID: framework.IDAttribute() only when the AWS API returns an Id field. Flag schemas that include it on ARN-identified resources just by habit.
ForceNew)Plugin Framework uses plan modifiers, not ForceNew. Flag any new Framework code that mentions ForceNew.
stringplanmodifier.RequiresReplace() — replaces ForceNew: truestringplanmodifier.UseStateForUnknown() — keeps a computed value stable across plansMaxItems/MinItemsUse listvalidator.SizeAtMost(N) / SizeAtLeast(N) (and setvalidator equivalents) on the block, not MaxItems/MinItems on the attribute. For a single nested object, combine listvalidator.SizeAtMost(1) with a list nested block.
schema.ListNestedBlock requires CustomType: fwtypes.NewListNestedObjectTypeOf[complexArgumentModel](ctx). The model field is fwtypes.ListNestedObjectValueOf[complexArgumentModel]. Flag nested blocks that omit CustomType.
For sets of strings, use CustomType: fwtypes.SetOfStringType with fwtypes.SetValueOf[types.String].
For AWS API map blocks, the provider schema has no map-of-objects type — use MapBlockKey. Flag attempts to model AWS map blocks with schema.MapAttribute.
Mark credentials, tokens, and write-only secrets Sensitive: true. Flag computed or required attributes that obviously hold secret material but aren't marked sensitive.
Resources with configurable timeouts use timeouts.Block(ctx, timeouts.Opts{Create: true, Update: true, Delete: true}) and set defaults via r.SetDefaultCreateTimeout / SetDefaultUpdateTimeout / SetDefaultDeleteTimeout that reflect AWS API behavior — RDS Create can take 30–60 minutes; an EC2 SG takes seconds. Don't use arbitrary round numbers. Data sources and list resources do not expose configurable timeouts.