.agents/skills/review-lifecycle/SKILL.md
Assume the @maintainer persona. Scope: CRUD, errors, AutoFlex on non-test resource code (internal/service/**/*.go). Loaded from review-pr.
One above each factory function. Flag missing annotations or factory-name/resource-name mismatches.
| Construct | Annotation |
|---|---|
| Resource (Framework) | // @FrameworkResource("aws_<svc>_<thing>", name="<Human Name>") |
| Data source (Framework) | // @FrameworkDataSource("aws_<svc>_<thing>", name="<Human Name>") |
| List resource (Framework) | // @FrameworkListResource("aws_<svc>_<thing>") |
| List resource (SDKv2) | // @SDKListResource("aws_<svc>_<thing>") |
type fooResource struct {
framework.ResourceWithModel[fooResourceModel]
framework.WithTimeouts // only when a timeouts block is present
framework.WithImportByIdentity // not WithImportByID for new resources
}
framework.WithImportByIdentity. Flag framework.WithImportByID on new resources.framework.ResourceWithModel[T] (not ResourceWithConfigure).framework.DataSourceWithModel[T].Create: get client → fetch plan → flex.Expand → set tags via input.Tags = getTagsIn(ctx) for tagged resources → AWS Create call → flex.Flatten output back into the plan → wait → resp.State.Set(ctx, plan). Flag Creates that don't read the output back into the plan — computed attributes stay unknown in state.
Read: get client → fetch state → finder → on retry.NotFound(err), append fwdiag.NewResourceNotFoundWarningDiagnostic(err), call resp.State.RemoveResource(ctx), return → flatten → resp.State.Set.
Update: get client → fetch plan and state → diff, d := flex.Diff(ctx, plan, state) → gate on diff.HasChanges() → AWS modify → flatten output back into plan → wait → resp.State.Set(ctx, &plan). Flag updates that always call the API without HasChanges(), or that re-fetch state after the modify.
Omit Update when the API has no update, every attribute has RequiresReplace(), or Create is reused for modify.
Delete: get client → fetch state → build input → AWS delete; silently swallow errs.IsA[*awstypes.ResourceNotFoundException](err) → wait.
Use smerr/smarterr, never raw resp.Diagnostics.AddError.
smerr.AddEnrich(ctx, &resp.Diagnostics, req.Plan.Get(ctx, &plan)) (not the deprecated EnrichAppend).smerr.AddError(ctx, &resp.Diagnostics, err, smerr.ID, plan.Name.String()). Always pass smerr.ID with an identifier — plan.Name in Create, state.ID elsewhere.smarterr.NewError(err).errs.IsA[*awstypes.<Exception>](err) — never type assertions, never strings.Contains(err.Error(), ...).retry.NotFound(err) for wrapped not-found from the finder layer.Flag raw resp.Diagnostics.AddError, type assertions on AWS errors, and string-based error matching.
Use flex.Expand / flex.Flatten for model ↔ SDK conversion. Manual per-field aws.String / aws.ToString is wrong in new Framework code.
flex.WithFieldNamePrefix("<Thing>") when AWS prefixes its fields (model ID ↔ SDK ThingId).Parameters ↔ parameter).review-tags.flex.Diff(ctx, plan, state) then diff.HasChanges().