Skip to content

Tags: BlackbirdWorks/gopherstack

Tags

v15.0.0

Toggle v15.0.0's commit message

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature.
parity: full 154-service AWS-emulation sweep (single PR) (#2342)

* parity-sweep: seed single-PR tracking checklist (154 services)

* parity(ec2): real AWS-accurate EC2 emulation — fix parity.md ec2 findings

RevokeSecurityGroupEgress rule validation (InvalidPermission.NotFound), DescribeInstances allocation perf, and remaining ec2 Parity/Performance/Leak findings. Table-driven tests. build+vet+test+lint green.

* parity(s3): real AWS-accurate S3 emulation — fix parity.md s3 findings

CompleteMultipartUpload empty-parts rejection, S3 Select validation, list pagination, object-lambda/tags leak fixes, replication goroutine drain on Shutdown. 9 table-driven test funcs / 18 sub-cases. build+vet+test+lint green.

* parity-sweep: tick ec2, s3 complete

* parity(cloudformation): real AWS-accurate CFN emulation — fix parity.md findings

DescribeType full schema, StackSet drift ops (DetectStackSetDrift/ListStackSetOperations/DescribeStackSetOperation), event/stack/operation eviction caps. Table-driven tests. build+vet+test+lint green.

* parity(sns): real AWS-accurate SNS emulation — fix parity.md findings

RedrivePolicy/DLQ delivery, DLQ target validation, archive/replay history, region isolation, pagination, FIFO dedup, seq-counter cleanup. Table-driven tests. build+vet+test+lint green.

* parity-sweep: tick cloudformation, sns complete

* parity(lambda): real AWS-accurate lambda emulation — fix parity.md findings

Parity fixes:
- handleInvokeAsync: fire-and-forget (HTTP 202 immediately, asyncWG.Go for background invocation)
- handleInvokeWithResponseStream: proper AWS event stream binary protocol (CRC32/IEEE frames)
- sweepESMs: mark enabled ESMs with missing functions as LastProcessingResult="PROBLEM"

Performance / leak fixes:
- withInvocationChain: []string slice (make+copy) instead of map — no per-call heap alloc
- invocationChainContains: slices.Contains — cleaner hot-path
- activeConcurrencies: delete map entry when count reaches zero
- cleanupSem / logSem: replaced with fresh channels in Reset() so post-reset goroutines
  don't block on pre-reset channel references

Lint / modernize:
- Remove //nolint annotations: use loop counters for int→byte/uint16 narrowing (G115)
- WaitGroup.Go, maps.Copy, slices.Contains modernize patterns
- nlreturn, goconst, gocritic, govet shadow, testifylint, revive fixes

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* parity(dynamodb): real AWS-accurate DynamoDB emulation — fix parity.md findings

PITR snapshot capture, GSI/LSI LastEvaluatedKey base-keys, PartiQL NextToken/ORDER BY/DuplicateItem/error-codes, ExecuteTransaction atomicity, export/import async status, restore GSI/LSI/billing fidelity, OnDemandThroughput, expr cache (parse-once), backup/iterator leak fixes. 65 files, table-driven tests. build+vet+test+lint green.

* parity(lambda): real AWS-accurate Lambda emulation — fix parity.md findings

Durable-execution + capacity-provider ops implemented (no more no-op stubs), SnapStart, CreateFunction Pending->Active state + LastUpdateStatus, memory validation, ESM health checking. Table-driven tests. build+vet+test+lint green.

* parity-sweep: tick dynamodb, lambda complete

* parity(stepfunctions): real AWS-accurate Step Functions emulation — fix parity.md findings

TestState nextState, real MapRun data (Describe/List/UpdateMapRun), O(1) status-filtered ListExecutions, SweepTaskTokens lock fix, orphaned-tombstone cleanup, history TTL. Table-driven tests. build+vet+test+lint green.

* parity-sweep: tick stepfunctions complete

* parity(ssm): fix parity, performance, and leak issues

Parity:
- Replace shared package-level mock KMS key with per-instance random
  AES-256 key (newInstanceGCM). Each InMemoryBackend now generates its
  own key so ciphertexts are not interchangeable across backend
  instances, matching AWS KMS key-isolation semantics.

Performance:
- Remove O(n) expireCommandsLocked call from SendCommand write path;
  expired-command eviction is the janitor's job (sweepExpiredCommands
  runs on a configurable interval). SendCommand is now O(1) again.
- Remove paramNamesSorted sorted-slice index and its O(n) insert on
  every PutParameter. Replace collectPathParamsSorted (binary-search)
  with collectPathParams (linear scan + sort-at-read). PutParameter
  write path drops from O(n) to O(1); GetParametersByPath is O(n log n)
  which is acceptable for an emulator. Also fixes a silent post-Restore
  bug where GetParametersByPath returned empty (sorted slice was never
  rebuilt from the snapshot).

Leaks:
- Add cleanupEmptyParamRegion: after DeleteParameter / DeleteParameters
  removes the last entry in a region, the empty parameters/history/tags
  inner maps are deleted so they don't accumulate indefinitely.

Tests:
- Update leak_test.go: TestSendCommand_PrunesExpiredCommands →
  TestJanitor_PrunesExpiredCommands; verify janitor sweeps expired
  commands and that SendCommand no longer does so.
- Add parity_fixes_test.go with table-driven tests for all four fixes:
  per-instance key isolation, self-roundtrip encryption, linear-scan
  path lookup (sort order, recursive/non-recursive, no-match), and
  region-map cleanup via single and batch delete.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* fix(iam): parity fixes — distinct error sentinels, O(1) sorted list indexes, fast policy lookup

Parity:
- Give each NoSuchEntity sentinel a distinct message suffix (user, role, policy,
  group, access key, instance profile, inline policy, SAML provider, OIDC provider,
  login profile) so callers can identify the missing resource type via .Error()
  inspection without relying on errors.Is pointer identity alone. HTTP error code
  is still "NoSuchEntity" matching AWS.
- Fix collectNamedEntityPolicies to use policyByARN map for O(1) ARN → name
  resolution instead of the previous O(n) linear scan over all policies.

Performance:
- Add sortedUserNames, sortedRoleNames, sortedPolicyNames, sortedGroupNames,
  sortedIPNames []string indexes to InMemoryBackend, maintained via binary-search
  insert/delete on every create/delete. ListUsers, ListRoles, ListPolicies,
  ListGroups, ListInstanceProfiles now paginate via pageFromSortedNames which
  resolves the base64-encoded integer marker token in O(1) and builds each page
  in O(k) (page size), eliminating the previous O(n log n) sort rebuild on every
  list call.
- rebuildIndexesLocked and Purge both rebuild sorted name indexes via
  rebuildSortedNames, keeping persistence and compaction paths consistent.

Tests:
- TestParityIAM_ErrorSentinelDistinctness: table-driven, verifies each sentinel
  has a unique .Error() string.
- TestParityIAM_ErrorSentinelUniqueness: all pairs are not-equal via errors.Is.
- TestParityIAM_ErrorSentinelWrapping: backend errors wrap the correct sentinel.
- TestParityIAM_HandlerNoSuchEntityCode: handler returns 400 + "NoSuchEntity"
  for all not-found operations.
- TestParityIAM_SimulatePrincipalPolicy: real policy evaluation (allow, deny,
  no policy, explicit deny overrides allow).
- TestParityIAM_CredentialReportColumns: all 22 AWS-required CSV columns present.
- TestParityIAM_ListPaginationSortedOrder: multi-page pagination stays sorted.
- TestParityIAM_SortedIndexMaintainedAfterDelete: index correct after deletion.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* parity(ssm): complete parity.md findings — region cleanup, MW executions, generic cleanup helper

- Add cleanupEmptyInnerMap[V any] generic helper that removes a region key
  from any two-level map when the inner map becomes empty; replaces the
  three-field cleanupEmptyParamRegion body with calls to this helper
- Wire cleanup to all delete paths: DeleteActivation, DeleteAssociation,
  DeregisterTargetFromMaintenanceWindow, DeregisterTaskFromMaintenanceWindow,
  DeleteMaintenanceWindow, DeletePatchBaseline, DeleteOpsItem, DeleteOpsMetadata,
  DeleteInventory, DeleteResourceDataSync, DeleteResourcePolicy, DeleteDocument
- Janitor sweepExpiredCommands now cleans up commands/commandInvocations maps
  after eviction so empty region buckets do not accumulate
- GetMaintenanceWindowExecution/Task/Invocation now populate StartTime, EndTime,
  StatusDetails, TaskARN, TaskType, Priority, MaxConcurrency, MaxErrors,
  InvocationID, WindowTargetID from stored window/task data
- Expand three MW execution output types with full AWS-accurate fields
- Fix handler_batch2_test to create a real window before GetMaintenanceWindowExecution
- Add TestGetMaintenanceWindowExecution_FullOutput and TestOtherMapsRegionCleanup
  table-driven tests covering new behavior (all t.Parallel)
- Zero golangci-lint issues; struct field order corrected by fieldalignment

* parity(ssm): real AWS-accurate SSM emulation — implement stubbed ops + fixes

~120 stubbed ops given real state mutation (ResourceDataSync, Inventory, Activations, maintenance windows w/ MaxConcurrency/MaxErrors/InvocationID/WindowTargetID), GetParametersByPath prefix index, param/doc/command history AWS caps, MaxResults bounds. Table-driven tests, 0 lint.

* parity(iam): real AWS-accurate IAM emulation — fix parity.md findings

Policy-eval correctness, pagination/validation fidelity, sub-ops. Table-driven tests, 0 lint.

* parity(glue): real AWS-accurate Glue emulation — implement stubbed ops

20+ empty-struct stubs given real data/state (GetBlueprintRun, GetPlan, ImportCatalogToGlue, column-statistics, schema-versions-diff, usage-profile), StopCrawler STOPPING->READY reconcile. Table-driven tests, 0 lint.

* parity-sweep: tick ssm, iam, glue

* parity(kms): fix cache staleness, lastUsage leak, perf O(n) clear

Four parity/leak/perf fixes for services/kms:

Parity: keyIDResolutionCache not invalidated on DisableKey /
ScheduleKeyDeletion. Alias→keyID entries cached before a key state
change persisted in the cache, allowing stale hits to bypass the
aliasesStore and return the old keyID. Fix: call evictAliasesFromCache
(O(aliases-for-key)) in both operations.

Performance: clearResolutionCache used sync.Map.Range+Delete (O(n)) and
was called on every alias mutation (Create/Update/Delete). Fix: change
keyIDResolutionCache to *sync.Map so clearResolutionCache swaps the
pointer in O(1); replace full-cache clears in alias mutations with
single targeted Delete calls; remove the post-sweep clearResolutionCache
call from sweepExpiredKeys since purgeKey now evicts targeted entries.

Leaks: purgeKey in the janitor deleted keys, aliases, grants, and key
material but never removed the corresponding lastUsage sync.Map entry,
causing unbounded growth. Fix: add lastUsage.Delete in purgeKey.

Tests: table-driven tests in parity_fixes_test.go covering all four
fixes; test helpers (ResolutionCacheLen, ResolutionCacheHas,
LastUsageExists) added to export_test.go.

* parity(cloudwatch): real AWS-accurate CloudWatch emulation — fix parity.md findings

Parity:
- GetMetricWidgetImage: return minimal valid 1×1 PNG (base64) instead of empty stub
- ListAlarmMuteRules: add backend method + wire handler to return stored rules
- ListManagedInsightRules: add backend method filtering ManagedRule=true; wire handler
- PutManagedInsightRules: parse ManagedRules.member.N.* and store with ManagedRule=true
- EC2/AutoScaling alarm actions: log explicit warnings instead of silent no-op

Performance:
- SweepExpiredMetrics: two-phase sweep (read-lock snapshot → out-of-lock filter → write-lock apply)
  avoids holding global write lock for full O(series×points) scan
- PutMetricData: extract storeDatum helper; move stream delivery timestamp update to a
  second, shorter write-lock acquisition outside the main metrics write section
- Extract sweepScanCandidates / sweepApplyResults / hasExpiredPoint helpers to reduce
  cognitive complexity below gocognit threshold

Leaks:
- deleteResourceTags: call t.Close() before removing from map to deregister the
  per-resource Prometheus lockmetrics entry and prevent unbounded registry growth

Tests: new parity_test.go with table-driven tests for all fixed ops

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* parity(ecs): real AWS-accurate ECS emulation — implement daemon ops, service revisions, state changes

- Implement all 12 daemon CRUD operations with full state tracking (CreateDaemon,
  DeleteDaemon, DescribeDaemon, ListDaemons, UpdateDaemon and task-def/deployment/revision ops)
- Track service revisions on CreateService and UpdateService; implement DescribeServiceRevisions
- Fix DiscoverPollEndpoint to return region-specific endpoints (was hardcoded)
- Implement SubmitTaskStateChange, SubmitContainerStateChange, SubmitAttachmentStateChanges
  with cluster/task validation instead of no-op stubs
- Fix enrichCluster O(n) task scan: cache RunningTasksCount/PendingTasksCount on Cluster
  and maintain counters at every state transition (RunTask, StopTask, startTasksOutsideLock)
- Add Backend interface methods for all new ops; add GetRegion() on InMemoryBackend
- Add region field to Handler populated from backend for regional URL generation
- 19 table-driven tests covering all new operations and counter correctness

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* parity(cloudwatch): real AWS-accurate CloudWatch emulation — fix parity.md findings

findGrantByToken token index (O(1)), metric-datapoint ring buffer, alarmHistory cross-alarm cap. Table-driven tests. build+vet+test+lint green.

* parity-sweep: tick cloudwatch

* refactor(kms): split ReEncrypt into helpers to satisfy funlen lint

Extract reEncryptDecrypt (source key lookup, validation, decrypt) and
reEncryptEncrypt (dest key lookup, validation, encrypt) so ReEncrypt
itself is ~34 lines, well under the 100-line funlen limit.

No behaviour change.

* parity(kms): real AWS-accurate KMS emulation — fix parity.md findings

findGrantByToken O(1) token index, keyMaterialHistory migration (decrypt older ciphertexts), grant/material leak fixes, ReEncrypt refactored under funlen. Table-driven tests. build+vet+test+lint green.

* parity(ecs): real AWS-accurate ECS emulation — fix parity.md findings

getServicesForReconciler bounded iteration, docker containers map leak on failed StopTask, reconciler perf. Table-driven tests across 28 files. build+vet+test+lint green.

* parity-sweep: tick kms, ecs

* parity(sts): real AWS-accurate STS emulation — fix parity.md findings

GetCallerIdentity InvalidClientTokenId (400 not 403), session TOCTOU fix, session-store sweep/leak bound. Table-driven tests. build+vet+test+lint green.

* parity-sweep: tick sts

* fix(sqs): parity/perf — region isolation, janitor skip-idle, MD5 reuse

Parity:
- lookupQueueByURL: remove O(n) URL-string fallback scan that defeated region
  isolation; always resolve via effectiveRegion(region)+name composite key so a
  wrong-region request returns not-found instead of blindly finding the queue.

Performance:
- pruneState: replace full-capacity snapshot (len(b.queues)) with a filtered
  collection that skips queues with no hasActivity flag set. A new atomic.Bool
  field on Queue is set on every SendMessage and cleared by pruneState when the
  queue becomes fully idle, so idle queues are skipped on subsequent janitor
  ticks without lock contention.
- ReceiveMessage handler: when filterMsgAttrs returns the full attribute set
  (len(returnedAttrs)==len(msg.MessageAttributes)), reuse msg.MD5OfMessageAttributes
  computed at send time instead of re-sorting and re-hashing on every receive.
  Subset requests still recompute to produce a correct scoped digest.

Tests (table-driven):
- TestLookupQueueByURL_RegionIsolation: wrong-region receive returns error
- TestLookupQueueByURL_CrossRegionURLScanEliminated: east queue invisible to west
- TestPruneState_SkipsIdleQueues: 50 idle queues, active-queue message expires
- TestPruneState_ClearsActivityFlagWhenIdle: flag cleared after full drain
- TestComputeMD5OfMessageAttributes_FullSetUsesPrecomputed: all/.*/ exact-full variants
- TestReceiveMessage_MD5Consistency: subset MD5 matches SQS wire-format spec

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* parity(cloudwatchlogs): real AWS-accurate CW Logs emulation — fix parity.md findings

metric-filter matching index (O(filters+events) not O(×)), parsed-query cache TTL eviction. Table-driven tests. build+vet+test+lint green.

* parity(sqs): real AWS-accurate SQS emulation — fix parity.md findings

Table-driven tests. build+vet+test+lint green.

* parity-sweep: tick cloudwatchlogs, sqs

* parity(ecr): real AWS-accurate ECR emulation — fix parity.md findings

DescribeImages incremental digest->tags reverse map (no rebuild per call), InitiateLayerUpload TTL eviction. Table-driven tests. build+vet+test+lint green.

* parity-sweep: tick ecr

* parity(kinesis): fix tags leak, optimize janitor sweep, add shutdown mechanism and UI

* parity(kinesis): real AWS-accurate Kinesis backend — fix parity.md findings

tags-map cleanup via OnStreamPurged on all delete paths, janitor sweepRetention RLock (no longer blocks PutRecord/GetRecords), explicit janitor Stop() shutdown. (Existing UI page preserved; gemini's unprompted UI rewrite dropped.)

* parity(route53): implement advanced ops, fixes and UI

* parity-sweep: tick kinesis (backend)

* parity(route53): real AWS-accurate Route53 emulation — fix parity.md findings

handler-level tags map eviction on missed/failed ARN deletes, completeness ops, UI additions. Table-driven tests. (stray fix_lint.sh excluded.)

* parity(glacier): real AWS-accurate Glacier emulation — fix parity.md findings

async retrieval-job window before GetJobOutput (no instant Succeeded), ListVaults/ListArchives marker copy fix. Table-driven tests. (stray backend.go.orig excluded.)

* feat(lakeformation): parity fixes for GetDataLakePrincipal, GetTableObjects, GetQueryStatistics, GetWorkUnitResults, and performance/leak improvements

* parity-sweep: tick route53, glacier

* parity(lakeformation): real AWS-accurate LakeFormation emulation — fix parity.md findings

permissions slice cap/TTL (no unbounded growth), backend accuracy. Table-driven tests. build+vet+test+lint green.

* parity-sweep: tick lakeformation

* parity(macie2): real AWS-accurate Macie2 emulation — fix parity.md findings

findings-criteria matching, list pagination + generic listPaginated helper, accuracy. Table-driven tests. build+vet+test+lint green. (stray patch_backend.sh excluded.)

* parity-sweep: tick macie2

* parity(rds): real AWS-accurate RDS emulation — fix parity.md findings

Marker pagination for DescribeDBParameterGroups/DBClusterParameterGroups/DBParameters/OptionGroups, UI additions. Table-driven tests. build+vet+test+lint green. (stray .orig + package-lock excluded.)

* parity-sweep: tick rds

* parity(rds): remove orphan handler_stubs.go (renamed to handler_completeness.go) — fix duplicate-decl build break

* parity(organizations): real AWS-accurate Organizations emulation — fix parity.md findings

ListTargetsForPolicy summary caching, CreateOrganizationalUnit sibling-name scan perf, pagination. Table-driven tests. build+vet+test+lint green.

* parity-sweep: tick organizations

* fix(integration): STS/CloudWatchLogs/ECR runtime regressions (go-ds2ym)

DecodeAuthorizationMessage decodes any valid base64 (not just self-issued), AssumeRoleWithSAML creds/Issuer/NameQualifier, CloudWatchLogs Insights, ECR GetAuthorizationToken. Unit+lint green.

* fix(integration): correct STS DecodeAuthorizationMessage/AssumeRoleWithSAML + ECR GetAuthorizationToken

Supersede the incomplete first attempt: STS decodes any valid base64 (not only self-issued), SAML accepts non-XML base64 assertions, ECR returns stable base64(AWS:dummy-password). Unit tests realigned. CloudWatchLogs Insights still pending.

* fix(integration): CloudWatchLogs StopQuery allows stopping instant-Complete queries

gopherstack runs Insights queries synchronously, so a query is already Complete
when a client calls StopQuery — the old running-state guard rejected it. StopQuery
now transitions any non-cancelled query to Cancelled (matches TestIntegration_CloudWatchLogs_Insights).

* parity(batch): real AWS-accurate Batch emulation — fix parity.md findings

DeleteComputeEnvironment/findTagsInCoreResources reverse-index perf, accuracy. Table-driven tests. build+vet+test+lint green. (stray patch_backend.go/sweep_test.go/handler.go.orig excluded.)

* parity-sweep: tick batch

* parity(elasticache): real AWS-accurate ElastiCache emulation — fix parity.md findings

backend accuracy + lock-correctness fixes. Table-driven tests. build+vet+test+lint green.

* parity-sweep: tick elasticache

* parity(xray): fix all parity.md findings

- NewInMemoryBackend(accountID, region) — ARNs now use the injected
  region/account instead of hardcoded config.DefaultRegion constants
- groupsByARN index — GetGroupByARN/UpdateGroupByARN/DeleteGroupByARN
  go from O(n) linear scan to O(1) map lookup
- Insight detection — PutTraceSegments now calls detectInsights();
  ACTIVE insights auto-open when per-service fault rate ≥ 5% over a
  60-second window and auto-close when the rate normalises
- ListRetrievedTraces — handler now returns real Segments[]
  (Document + Id + computed Duration) instead of empty arrays
- Retrieval leak fix — janitor sweepExpiredTraces now also evicts
  traceRetrievals/retrievedTraces entries older than TraceTTL
- provider.go uses service.AccountRegionOrDefault to populate backend
- Table-driven tests (t.Run + []struct) for all new behaviours

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* parity(workspaces): fix all parity.md findings (go-8189a)

- Add region field to storedWorkspace; store via regionFor(ctx) on CreateWorkspace
- Filter workspaces by region in DescribeWorkspaces
- Validate DirectoryID is registered in CreateWorkspace
- Add ctx param to CreateWorkspace, DescribeWorkspaces, DescribeWorkspaceBundles,
  DescribeWorkspaceDirectories; pass through from handlers
- Add cursor-based pagination to DescribeWorkspaceBundles (page size 25)
- Add cursor-based pagination to DescribeWorkspaceDirectories (page size 50)
- Convert hardcodedBundles() to pre-sorted amazonBundleList() function
- Refactor handleCreateWorkspaces into validateCreateWorkspacesInput,
  specToCreationSpec, wsToPending helpers to stay under funlen threshold
- Update existing tests to register directories before CreateWorkspaces
- Add backend_parity_test.go with 5 table-driven parity tests

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* parity-sweep: tick workspaces, xray (completed)

* chore: remove trash fix_lint.sh from parity-sweep

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* parity(dax): fix AZ-indexing, RebootNode recovery, pending-reboot, error mapping

- IncreaseReplicationFactor: guard used raw loop index i instead of
  offset j=i-existingCount, silently ignoring caller-supplied AZs
  when the cluster already had nodes
- RebootNode: empty NodeId returned ErrNodeNotFound; AWS returns
  InvalidParameterValue. Add recovery goroutine that restores node
  status to available after 1s, mirroring real DAX behaviour
- UpdateParameterGroup: did not mark dependent clusters pending-reboot
  or populate NodeIDsToReboot; now scans all clusters using the group
- writeBackendError: flattened every DynamoDB error to ValidationException;
  now maps ConditionalCheckFailed, ResourceNotFound, TransactionCanceled,
  TransactionConflict, and ProvisionedThroughputExceeded to their
  correct DAX error codes
- handleGetItem: decoded ConsistentRead from the wire but discarded it
  with _; now passes it through to the DynamoDB backend
- nameRef: O(n²) linear scan replaced with O(1) reverse map
- schemaFor: cache was never invalidated on table drop/recreate;
  now fetches live on every call for correctness

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

Executed-By: gopherstack/polecats/amber

* fix(sqs): hold q.mu around computeDynamicAttributes in GetQueueAttributes

GetQueueAttributes read q.messages, q.delayedCount, and q.inFlightMessages
without holding q.mu, while ReceiveMessage writes them under q.mu.Lock.
This caused a data race detected by -race in TestIntegration_Lambda_SQS_ESM.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* parity(pinpoint): fix handleCreateApp error mapping

Before this change, any error from Backend.CreateApp was unconditionally
mapped to HTTP 500. Other handlers (GetApp, DeleteApp, etc.) already
dispatched errors correctly. This fix brings CreateApp into line:

- ErrInvalidParameter → 400 BadRequestException
- ErrConflict         → 409 ConflictException
- ErrNotFound         → 404 NotFoundException
- other               → 500 InternalServerErrorException

Add handler_parity_test.go with table tests covering:
- CreateApp input validation returns 400 (not 500)
- GetApp/DeleteApp for nonexistent IDs return 404 with NotFoundException
- CreateApp response shape includes Id, Arn, Name, CreationDate
- GetApps reflects all created apps
- DeleteApp removes app from subsequent list

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

Executed-By: gopherstack/polecats/amber

* feat(eventbridge): fix parity issues — opaque tokens, per-account quota, ListEventBuses Limit, Shutdown cancellation, tag leak

- paginate: encode next-page tokens as base64 so they are opaque to callers,
  matching real AWS behavior; parseNextToken retains a plain-integer fallback
  for tokens produced before this change
- paginateN: new generic helper that respects a caller-supplied page size (0 = default 100)
- ListEventBuses: add limit parameter to StorageBackend interface and InMemoryBackend
  so the Limit field from API requests is honored instead of always paging at 100
- CreateEventBus quota: count custom buses across all regions in b.buses to enforce
  the per-account limit (200), not per-region
- StartWorker: derive a cancellable context for scheduler and archiveJanitor goroutines;
  store the cancel func so Shutdown can terminate both workers before closing the backend
- DeleteEventBus / DeleteRule: describe the resource before deletion to obtain its ARN,
  then call clearResourceTags so the handler tags map does not grow without bound

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* parity(ram): opaque tokens, resourceOwner/type filters, policy accuracy, promote permission

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* parity(opsworks): implement missing AWS OpsWorks ops — stacks, layers, instances, apps, deployments

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* parity(personalize): implement missing AWS Personalize ops + accuracy fixes

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* parity(mediastore): container/policy/metric/lifecycle accuracy + audit coverage

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* parity(medialive): implement missing AWS MediaLive ops — inputs, channels, multiplex, input-devices

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* parity(mediapackage): channel/origin-endpoint/harvest-job accuracy + audit coverage

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* parity(guardduty): detector/finding/filter/IPSet accuracy + audit coverage

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* parity(fsx): filesystem/backup/storage-virtual-machine accuracy + audit coverage

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* parity(identitystore): user/group/membership accuracy + filters + audit coverage

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* parity(elbv2): listener/rule/target-group/health accuracy + audit coverage

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* parity(emr): implement missing AWS EMR ops — steps, instance groups/fleets, security configs

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* parity(docdb): cluster/instance/snapshot/parameter-group accuracy + audit coverage

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* parity(elasticbeanstalk): application/environment/version/config accuracy + audit coverage

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* parity(datasync): location/task/execution/agent accuracy + audit coverage

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* parity(ddbstreams): real stream timestamps, StreamLabel, error namespace

- store.go: add StreamCreatedAt time.Time field to Table
- streams_ops.go: buildStreamARNInRegion now accepts creation time, embeds
  real ISO 8601 millisecond timestamp (e.g. 2026-06-26T03:43:00.000) in the
  stream ARN instead of the hardcoded 2024-01-01 placeholder
- streams_ops.go: DescribeStream sets StreamLabel from ARN (not "latest"),
  populates CreationRequestDateTime with the real stream creation time
- streams_ops.go: ListStreams sets StreamLabel from ARN (not "latest")
- streams_ops.go: add streamLabelFromARN helper
- table_ops.go: CreateTable and UpdateTable set StreamCreatedAt and pass it
  to buildStreamARNInRegion
- handler.go (dynamodbstreams): rewrite error __type prefix from
  dynamodb.v20120810 to dynamodbstreams.v20120810 so SDK clients get the
  correct namespace
- handler_parity_test.go: table-driven parity tests covering ARN label
  format, StreamLabel consistency, CreationRequestDateTime presence,
  ListStreams label, error namespace, and UpdateTable stream enable

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

Executed-By: gopherstack/polecats/amber

* parity(kinesisanalytics): fix DeleteApplication error code and UpdateApplication response

- backend.go: DeleteApplication timestamp mismatch now returns ErrConcurrentUpdate
  instead of wrapping awserr.ErrConflict; fixes routing in handleError so the
  response is ConcurrentModificationException (not LimitExceededException)
- handler.go: UpdateApplication now returns *describeApplicationOutput containing
  the full ApplicationDetail rather than an empty struct; real AWS Kinesis Analytics
  returns the updated application detail in the response
- handler_parity_test.go: table-driven parity tests covering ConcurrentModification
  on timestamp mismatch, correct-timestamp delete succeeds, UpdateApplication body
  contains ApplicationDetail with updated code and incremented version, and error
  type mappings for all key error conditions

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

Executed-By: gopherstack/polecats/amber

* parity(managedblockchain): fix vote threshold, error codes, proposal actions

- Add Code field to errorResponse (ResourceNotFoundException etc)
- Fix applyVoteThresholdLocked to use float64 division (not integer)
- Fix rejection threshold: mathematically-impossible-to-approve logic
- Execute Invitation/Removal actions when proposal transitions to APPROVED
- Add status query-param filter to ListProposals
- Add parity tests covering all of the above

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

Executed-By: gopherstack/polecats/amber

* parity(iotanalytics): channel/datastore/pipeline/dataset accuracy + audit coverage

* parity(pipes): implement missing AWS EventBridge Pipes ops

- ConflictException (409) for start/stop when already at desired state
- ServiceQuotaExceededException when 1000-pipe limit is hit
- Enrichment field included in ListPipes summaries
- ValidationException for invalid NextToken base64
- Shared changePipeDesiredState to eliminate Start/Stop duplication
- Handler error routing for ErrConflict and ErrQuota

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

Executed-By: gopherstack/polecats/amber

* parity(iot): thing/certificate/policy/topic-rule/shadow accuracy + audit coverage

* parity(redshift): fix parity gaps in DescribeTags/DescribeClusters/DeleteCluster/DescribeClusterSnapshots

- DescribeTags: filter by ResourceName, ResourceType, TagKey, TagValue
  (previously ignored all filter parameters)
- DescribeClusters: filter by TagKey and TagValue
- CreateCluster: validate MasterUserPassword format when provided
  (8-64 chars, requires uppercase/lowercase/digit, forbids @/"/space/slash)
- DeleteCluster: respect SkipFinalClusterSnapshot=false + FinalClusterSnapshotIdentifier;
  create final snapshot before deleting when explicitly requested
- DescribeClusterSnapshots: add MaxRecords/Marker pagination

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

Executed-By: gopherstack/polecats/amber

* parity(cognitoidp): user pool/client/user/group/auth-flow accuracy + coverage

* parity(apigateway): fix method/integration validation, stage protection, and UpdateUsage

- Add RequestParameters to putMethodInput and pass it through PutMethod
- Validate authorizationType (NONE/AWS_IAM/CUSTOM/COGNITO_USER_POOLS);
  require authorizerId when CUSTOM or COGNITO_USER_POOLS
- Validate integration type (AWS/AWS_PROXY/HTTP/HTTP_PROXY/MOCK)
- FlushStageCache now validates API + stage existence before returning 202
- DeleteDeployment now blocks deletion when a stage references the deployment
- UpdateUsage validates usage plan + key existence (was a no-op stub)
- Add routing for PATCH /usageplans/{id}/keys/{keyId}/usage -> UpdateUsage
- Extract IntegrationTypeMock, AuthTypeCognitoUserPool etc. as constants
- Fix proxy_test.go to use backend directly for UNKNOWN_CUSTOM integration setup
- Fix existing tests that expected deletion of stage-referenced deployments
- Add handler_parity_test.go with table-driven parity tests for all the above

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

Executed-By: gopherstack/polecats/amber

* parity(omics): store/workflow/run accuracy + coverage

* parity(secretsmanager): fix staging labels, cancel rotation, tag limit, replication

- PutSecretValue: honor caller's VersionStages exactly; when caller specifies
  only AWSPENDING (rotation createSecret step), don't force AWSCURRENT onto
  the new version and don't rotate the existing AWSCURRENT label
- PutSecretValue/CreateSecret: reject requests providing both SecretString
  and SecretBinary (InvalidParameterException, real AWS behavior)
- CancelRotateSecret: remove only AWSPENDING label; do not set RotationEnabled=false —
  real AWS keeps rotation config intact after cancel
- TagResource: count net new tag keys only; updating existing keys doesn't
  increase the total toward the 50-tag limit
- ReplicateSecretToRegions: return ResourceExistsException when replica already
  exists in target region and ForceOverwriteReplicaSecret is false
- GetSecretValue: include LastAccessedDate in output (was tracked but not returned)
- BatchGetSecretValue: reject when both SecretIdList and Filters are provided;
  switch filter matching from exact to prefix (consistent with ListSecrets)
- Extract resolveStagingLabels helper to keep PutSecretValue below gocognit limit
- Fix affected tests to assert real AWS behavior

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

Executed-By: gopherstack/polecats/amber

* parity(cloudfront): distribution/origin/behavior/invalidation accuracy + coverage

* parity(sagemaker): fix missing validations and extend compilation/automl job structs

- CreateModel: reject requests that provide both PrimaryContainer and Containers
  (real AWS returns ValidationException for this combination)
- UpdateNotebookInstanceFull: require Stopped status before accepting updates
  (real AWS rejects updates on InService/Pending/Stopping notebooks)
- CompilationJob: add InputConfig, OutputConfig, StoppingCondition fields and
  SetCompilationJobExtras; handler now captures and persists these at create time
- AutoMLJob: add OutputDataConfig, AutoMLJobObjective fields and
  SetAutoMLJobExtras; handler now captures and persists these at create time
- Fix handler_coverage_test to stop notebook before updating (matches real AWS flow)
- Add parity_c_test.go with 5 parity tests covering all new behaviors

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

Executed-By: gopherstack/polecats/amber

* parity(eks): cluster/nodegroup/fargate/addon accuracy + coverage

* parity(transfer): add missing ops and parity fixes for Transfer Family

- Add CertificateIDs to Profile struct and UpdateProfileFull method so
  UpdateProfile can persist certificate associations (real AS2 feature)
- Add CountUserSSHPublicKeys to backend and interface; populate
  SshPublicKeyCount in ListUsers response (real AWS includes this)
- Add UpdateAccessFull with full field support (PosixProfile,
  HomeDirectoryType, Policy, HomeDirectoryMappings) matching real AWS
- Add UpdateConnectorFull support for LoggingRole and SecurityPolicyName
- Add ImportCertificate TLS usage support (SIGNING/ENCRYPTION/TLS valid)
- Return Certificate body in DescribeCertificate when present
- Seed creation-time tags into tagsStore so ListTagsForResource sees them
- Replace global validWorkflowStepTypes var with isValidWorkflowStepType
  function to satisfy gochecknoglobals
- Add parity_b_test.go with table-driven parity tests for all new behavior

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

Executed-By: gopherstack/polecats/amber

* parity(mq): broker/configuration/user accuracy + coverage

* parity(efs): fix replication fields, destination lookup, and parity tests

- ReplicationDestination: add FileSystemArn, AvailabilityZoneName, KmsKeyID,
  OwnerId, LastReplicatedTimestamp, Status fields
- ReplicationConfiguration: add SourceFileSystemOwnerId field
- CreateReplicationConfiguration: auto-assign dest FSID/ARN, populate OwnerId
  and SourceFileSystemOwnerId from account ID
- DescribeReplicationConfigurations: search both source and destination FS IDs
- fsToResponse: add ValueInIA, ValueInStandard, ValueInArchive to SizeInBytes
- rcToResponse: emit SourceFileSystemOwnerId
- parity_a_test.go: 13 tests covering all identified behavioral gaps

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

Executed-By: gopherstack/polecats/amber

* parity(neptune): cluster/instance/snapshot/parameter-group accuracy + coverage

* parity(memorydb): add ExportSnapshot, fix User.ACLNames, Cluster field gaps

- Add ExportSnapshot operation (validates snapshot exists, returns it)
- Replace UserGroupCount with ACLNames []string in user response
- Add Engine field to User struct and userObject response
- Add ParameterGroupStatus (default "in-sync") to cluster response
- Add MultiRegionClusterName/MultiRegionParameterGroupName to Cluster struct
  and clusterObject response
- Update affected tests: UserGroupCount → ACLNames, op count 45 → 46
- parity_a_test.go: 8 parity tests covering all identified gaps

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

Executed-By: gopherstack/polecats/amber

* parity(swf): domain/workflow-type/execution/task accuracy + coverage

* parity(transcribe): fix JSON tags and add missing response fields

- Fix URI/ID JSON tags: MediaFileUri, RedactedMediaFileUri, SubtitleFileUris,
  VocabularyFileUri, VocabularyFilterFileUri, OutputEncryptionKMSKeyId,
  ChannelId — AWS uses lowercase-suffix casing, not Go acronym style
- Add Media field to transcriptionJobOutput (returned by Get/List/Start)
- Add DownloadURI and LastModifiedTime to GetVocabulary and GetMedicalVocabulary
- Add CreateTime, LastModifiedTime, UpgradeAvailability to language model output
- Add toLanguageModelOutput helper; use it in both Describe and List handlers
- Add parity_c_test.go covering all new fields and JSON key names

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

Executed-By: gopherstack/polecats/amber

* parity(translate): text/terminology/parallel-data/job accuracy + coverage

* parity(cloudtrail): fix response accuracy gaps

- Default RetentionPeriod to 2557 days (7 years) when not specified
- edsToMap: always include AdvancedEventSelectors (as [] when empty)
- GetEventSelectors: omit EventSelectors when AdvancedEventSelectors active
- GetTrailStatus: add TimeLoggingStarted/TimeLoggingStopped string fields
- StartImport/GetImport/StopImport: add CreatedTimestamp/UpdatedTimestamp
- DescribeQuery: add CreationTime field
- GetQueryResults: add QueryStatistics with TotalResultsCount/BytesScanned
- Add keyCreatedTimestamp/keyUpdatedTimestamp constants
- Add parity_a_test.go covering all new fields

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

Executed-By: gopherstack/polecats/amber

* parity(securityhub): hub/finding/insight/standard accuracy + coverage

* parity(backup): add VaultType, LastExecutionDate, IamRoleArn fields

- Vault struct gains VaultType field; set to BACKUP_VAULT on
  CreateBackupVault and LOGICALLY_AIR_GAPPED_BACKUP_VAULT on
  CreateLogicallyAirGappedBackupVault
- DescribeBackupVault and ListBackupVaults now return VaultType in
  responses; CreateLogicallyAirGappedBackupVault response also includes it
- GetBackupPlan now returns LastExecutionDate when UpdateTime is set,
  matching the existing ListBackupPlans behaviour
- ListBackupSelections items now include IamRoleArn, matching real AWS
- Add parity_a_test.go with 5 table-driven tests covering all three gaps

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

Executed-By: gopherstack/polecats/amber

* parity(athena): query-execution/workgroup/data-catalog/named-query accuracy + coverage

* parity(codebuild): fix missing ARNs, build inherits, overrides, filter groups, visibility alias

- BuildBatch: generate ARN on StartBuildBatch/RetryBuildBatch via batchARNIndex
- BatchGetBuilds: resolve ARN → ID via buildARNIndex for ARN-based lookup
- RetryBuild: copy ServiceRole, EncryptionKey, Timeout, Environment, Source, Phases from original
- StartBuild: introduce StartBuildConfig struct with buildspec/image/computeType/serviceRole/sourceVersion overrides
- UpdateProjectVisibility: return publicProjectAlias UUID on PUBLIC_READ
- ListCommandExecutionsForSandbox: return full CommandExecution objects instead of IDs
- BatchDeleteBuilds: populate buildsNotDeleted for missing IDs
- CreateWebhook/UpdateWebhook: accept and persist filterGroups
- Add parity_a_test.go covering all above gaps

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

Executed-By: gopherstack/polecats/amber

* parity(codepipeline): pipeline/execution/stage/action-type accuracy + coverage

* parity(codedeploy): revision round-trip, deploymentOverview, full RevisionLocation struct

- Add RevisionLocation struct (S3/GitHub/AppSpecContent sub-fields) to backend
- Store Revision in Deployment via DeploymentOptions.Revision
- GetDeployment and BatchGetDeployments now return revision and deploymentOverview
- deploymentOverview reflects synthetic counts based on deployment status
- Expand revisionLocationInput wire type with S3/GitHub/AppSpec sub-structs
- Add revisionFromWire/revisionToWire converters
- Add statusStopped constant (goconst); fix CommitId → CommitID (revive)
- Add parity_a_test.go: S3/GitHub revision round-trip, overview, ID format, stop status, computePlatform inherit

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

Executed-By: gopherstack/polecats/amber

* parity(appsync): graphql-api/schema/resolver/datasource accuracy + coverage

* parity(codecommit): fix blob shape, file history filtering, merge commit resolution

- GetDifferences: return afterBlob/beforeBlob as {blobId,path,mode} objects (not strings)
- ListFileCommitHistory: filter by filePath using per-file commit history tracking
- GetMergeCommit: prefer commit with both source+dest as parents over arbitrary commit
- Add fileHistory map to InMemoryBackend for path-based commit lookup
- Add parity_a_test.go covering blob shape, path filtering, and merge commit resolution

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

Executed-By: gopherstack/polecats/amber

* parity(comprehend): detection/classifier/recognizer/job accuracy + coverage

* parity(bedrock): fix foundation model ARN format, add modelLifecycle, ARN lookup

- Fix ARN format: was arn:aws:bedrock::{accountId}:foundation-model/..., now
  arn:aws:bedrock:{region}::foundation-model/... (region included, no account ID)
- Add FoundationModelLifecycle struct and modelLifecycle field to FoundationModelSummary
- Seed all foundation models with modelLifecycle.status = "ACTIVE"
- GetFoundationModel now matches by ARN in addition to model ID
- Add parity_a_test.go covering all three gaps

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

Executed-By: gopherstack/polecats/amber

* parity(cloudcontrol): resource CRUD + request-status accuracy + coverage

* parity(acm): fix SANs include primary domain, InUseBy always [], serial hex format

- SubjectAlternativeNames now always includes primary domain as first entry
  (buildSANList deduplicates; idempotency check updated to compare built list)
- DescribeCertificate InUseBy field is always a JSON array [], never null/omitted
- Certificate serial numbers use colon-separated hex pairs (e.g. "1a:2b:3c")
  matching real AWS ACM wire format; formatSerialHex helper replaces big.Int.Text
- Remove unused hexBase constant
- Add parity_a_test.go covering all three gaps with table-driven tests

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

Executed-By: gopherstack/polecats/amber

* parity(route53resolver): endpoint/rule/association/query-log accuracy + coverage

* parity(acmpca): add OwnerAccount/Serial to DescribeCA, END_DATE validity, chain fix

- DescribeCertificateAuthority now returns OwnerAccount (account ID) and
  Serial (CA cert serial hex) matching real AWS response shape
- IssueCertificate now accepts END_DATE and ABSOLUTE validity types
  (absolute epoch seconds), as used by Terraform aws_acmpca_certificate
- GetCertificate CertificateChain now concatenates CA cert + imported parent
  chain for subordinate CAs
- parity_a_test.go verifies all four behavioral differences

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

Executed-By: gopherstack/polecats/amber

* parity(s3control): access-point/job/storage-lens/public-access-block accuracy + coverage

* parity(appmesh): wrap single-resource responses under resource type key

Real AWS App Mesh wraps every Create/Describe/Update/Delete response
under the canonical resource type key (e.g. {"mesh": {...}}). All 28
single-resource handler methods now emit this wrapper.

Updated all existing tests in handler_audit1_test.go,
handler_audit2_test.go, and coverage_boost_test.go to unwrap before
asserting. Added parity_a_test.go verifying all 7 resource types and
all 4 CRUD operations produce the correct wrapper key.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

Executed-By: gopherstack/polecats/amber

* parity(servicediscovery): namespace/service/instance/operation accuracy + coverage

* parity(apprunner): expose InstanceConfiguration/SourceConfiguration in service output; fix DNSTarget on custom domain ops

serviceOutput now includes InstanceConfiguration (Cpu, Memory) and
SourceConfiguration (ImageRepository.ImageIdentifier) so DescribeService
returns the same fields as the real AWS App Runner API.

AssociateCustomDomain and DisassociateCustomDomain returned DNSTarget set
to the custom domain name being operated on; fixed to return the service
URL (e.g. <id>.<region>.awsapprunner.com) matching real AWS behavior.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

Executed-By: gopherstack/polecats/amber

* parity(amplify): app/branch/deployment/domain/webhook accuracy + coverage

* parity(appconfig): fix environment state to READY_FOR_DEPLOYMENT

Environment.State was initialized to "ReadyForDeployment" (camelCase) instead
of the correct "READY_FOR_DEPLOYMENT" (SCREAMING_SNAKE_CASE) used by the real
AWS AppConfig API. Added parity_a_test.go with table tests covering state
accuracy, resource IDs, deployment fields, sequential deployment numbers,
hosted config version headers, and Items key in list responses.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

Executed-By: gopherstack/polecats/amber

* parity(databrew): dataset/recipe/project/job accuracy + coverage

* parity(autoscaling): fix LB state, ASG status, tags, instance type, LC fields, step policies, lifecycle hooks

- lbStateAdded: "Added" → "InService" (Terraform polls for InService)
- ASG Status: remove "Active" default (AWS only sets Status during deletion)
- WarmPool Status: same fix
- xmlTag: add ResourceId/ResourceType fields (populated from ASG name in DescribeAutoScalingGroups)
- xmlInstance: add InstanceType field; makeInstances now looks up LC's InstanceType
- xmlAutoScalingGroup: add ServiceLinkedRoleARN (synthesized from account ID)
- xmlLaunchConfiguration: add UserData, KernelId, RamdiskId fields
- xmlScalingPolicy: add StepAdjustments, MinAdjustmentMagnitude
- handlePutScalingPolicy: parse StepAdjustments.member.N.* and MinAdjustmentMagnitude
- handleDescribePolicies: serialize StepAdjustments and MinAdjustmentMagnitude
- PutLifecycleHook: set GlobalTimeout = HeartbeatTimeout (numberOfRetries=1 default)
- PutScheduledUpdateGroupAction: generate ScheduledActionARN
- describeMetricCollectionTypesResult: add Granularities element with 1Minute
- parity_a_test.go: table tests covering all 11 gaps

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

Executed-By: gopherstack/polecats/amber

* parity(applicationautoscaling): scalable-target/policy/scheduled-action accuracy + coverage

* parity(awsconfig): fix all parity gaps — field casing, ARN generation, RecordingGroup, Scope, ComplianceSummary

- Fix ConfigRule JSON tags camelCase → PascalCase (ConfigRuleName, ConfigRuleArn, etc.)
- Remove bogus ConfigRule.ComplianceType field; default ConfigRuleState = "ACTIVE"
- Add ConfigRuleScope (ComplianceResourceTypes, TagKey, TagValue) to ConfigRule and handler
- Add RecordingGroup to ConfigurationRecorder with allSupported/includeGlobalResourceTypes/resourceTypes
- Add S3KeyPrefix and configSnapshotDeliveryProperties to DeliveryChannel
- Generate AggregationAuthorizationArn in PutAggregationAuthorization
- Generate ConfigurationAggregatorArn and accept AccountAggregationSources/OrganizationAggregationSource
- Generate ConformancePackArn and ConformancePackId; accept DeliveryS3Bucket/DeliveryS3KeyPrefix
- Populate lastStatus/lastStartTime fields in ConfigurationRecorderStatus
- Fix ListConfigurationRecorders to return []ConfigurationRecorderSummary (arn, name, recordingScope)
- Fix ListStoredQueries to return []StoredQueryMetadata (QueryArn, QueryId, QueryName)
- Fix DisassociateResourceTypes to pass ResourceTypes instead of empty string
- Fix ComplianceSummary shape to CappedCount/CapExceeded per real AWS API
- Fix ConfigRuleEvaluationStatus timestamps from float64 to string
- Add parity_a_test.go with 14 table-driven parity tests

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

Executed-By: gopherstack/polecats/amber

* parity(ce): cost-and-usage/forecast/anomaly/cost-category accuracy + coverage

* parity(appstream): add ComputeCapacityStatus, ImageName/Arn, IdleDisconnect, EnableDefaultInternetAccess to Fleet

Real AWS Fleet responses require ComputeCapacityStatus (Desired/Running/InUse/Available).
Fleet now stores and returns ImageName, ImageArn, IdleDisconnectTimeoutInSeconds, and
EnableDefaultInternetAccess. DescribeUsageReportSubscriptions response key fixed to
UsageReportSubscriptions (was Subscriptions). 22 parity table tests added.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

Executed-By: gopherstack/polecats/amber

* parity(codeartifact): domain/repository/package/version accuracy + coverage

* parity(cleanrooms): fix ID key names, ProtectedQuery status SUBMITTED, MemberAbilities in CreateMembership

- Add canonical "id", "membershipId", "collaborationId", "configuredTableId",
  "configuredTableAssociationId", "analysisTemplateIdentifier" dual-key fields
  to 22 response struct types in backend.go (backward-compat "*Identifier" keys
  kept alongside the AWS-canonical short keys)
- Fix ProtectedQuery and ProtectedJob initial status: "STARTED" → "SUBMITTED"
- Add memberAbilities []string to CreateMembership signature (interfaces.go,
  backend.go, handler.go) so abilities are persisted and returned
- Add parity_test.go with 13 tests covering dual-key fields, SUBMITTED status,
  MemberAbilities roundtrip, ARN format, tag lifecycle, and list summaries

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

Executed-By: gopherstack/polecats/amber

* parity(emrserverless): application/job-run accuracy + coverage

* parity(scheduler): Target in ListSchedules, FLEXIBLE window validation, EcsParameters networking fields

- Add Target {Arn, RoleArn} to scheduleSummary so ListSchedules items include
  the target summary that real AWS always returns
- Add validateFlexibleTimeWindow: when Mode=FLEXIBLE, MaximumWindowInMinutes must
  be >= 1; apply to both CreateSchedule and UpdateSchedule
- Add EcsParameters fields: NetworkConfiguration (with AwsvpcConfiguration),
  CapacityProviderStrategy, PlacementConstraints, PlacementStrategy, Tags
- Add corresponding handler structs and from/to conversion helpers
- Update handler_refinement2_test to pass MaximumWindowInMinutes when testing FLEXIBLE
- Add parity_b_test.go with 9 tests covering the three fix areas

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

Executed-By: gopherstack/polecats/amber

* parity(resourcegroups): group/query/tag/resource accuracy + coverage

* parity(resourcegroupstaggingapi): fix ComplianceDetails JSON field name, add ResourceARNList filter, fix DescribeReportCreation no-report status

- ComplianceDetails.KeysWithNoncompliantValues: fix JSON tag from
  KeysWithNonCompliantValues (wrong casing) to KeysWithNoncompliantValues
  to match the real AWS API spelling
- GetResourcesInput: add ResourceARNList []string field and apply filter
  in GetResources so callers can scope queries to specific ARNs
- DescribeReportCreation: return nil Status when no report exists instead
  of the non-AWS "NO REPORT" string; real AWS returns an empty response
- Update existing tests that asserted "NO REPORT" to expect nil Status
- Add parity_test.go covering all three gaps

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

Executed-By: gopherstack/polecats/amber

* parity(networkmonitor): monitor/probe accuracy + coverage

* parity(s3tables): fix ARN key casing, add type field, tableBucketArn in namespaces, wrap replication config, 204 for PutTableReplication

- keyTableARN: "tableARN" → "tableArn", keyTableBucketARN: "tableBucketARN" →
  "tableBucketArn" throughout all responses (CreateTable, GetTable, ListTables,
  CreateNamespace, GetTableBucketMaintenanceConfiguration, etc.)
- GetTableBucket and ListTableBuckets: add "type": "customer" field matching
  real AWS response for customer-owned table buckets
- GetNamespace and ListNamespaces: add tableBucketArn field to response per
  real AWS GetNamespace/ListNamespaces response shape
- GetTableBucketReplication: wrap destinations inside replicationConfiguration
  object instead of returning destinations at top level
- PutTableReplication: return 204 No Content with no body; real AWS returns
  HTTP 204, not 200 + status body
- Update all existing tests to use correct lowercase ARN key names
- Add parity_b_test.go with 8 tests covering all fixed gaps

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

Executed-By: gopherstack/polecats/amber

* parity(codeconnections): connection/host/sync-config accuracy + coverage

* parity(codestarconnections): fix VpcConfiguration, host status, tag response shape

- Add VpcConfiguration struct to backend/handler for CreateHost/UpdateHost
- Change initial host status from AVAILABLE to PENDING (real AWS behavior)
- Remove Tags from CreateConnection, GetConnection, CreateHost, GetHost,
  ListConnections, ListHosts responses; Tags only via ListTagsForResource
- GetHost omits HostArn (caller knows it); ListHosts items include HostArn
- Add host status constants: VPC_CONFIG_DELETING/FAILED/IN_PROGRESS
- Fix fieldalignment on VpcConfiguration and updateHostInput structs
- Update tests to reflect corrected AWS-accurate behavior

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

Executed-By: gopherstack/polecats/amber

* parity(cognitoidentity): identity-pool/identity/credentials/roles accuracy + coverage

* parity(serverlessrepo): omit empty semanticVersion in template/changeset responses

- Fix CreateCloudFormationTemplate response to omit semanticVersion when not
  provided (was serializing as empty string "")
- Fix GetCloudFormationTemplate response same way
- Fix CreateCloudFormationChangeSet response same way
- Add AddExpiredTemplateInternal test helper to exercise EXPIRED status
- Add handler_parity_b_test.go covering: EXPIRED template status, semanticVersion
  omission, GetApplication 404 on unknown version, templateUrl-only version create,
  duplicate version 409, ARN format, DeleteApplication 204, UnshareApplication
  missing orgId 400, ListApplicationVersions sort order, empty policy statements

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

Executed-By: gopherstack/polecats/amber

* parity(mwaa): environment/cli-token/web-login accuracy + coverage

* parity(textract): fix ListAdapters/Versions response shape, add QUERIES validation

- ListAdapters: remove Tags from summary, add FeatureTypes (matches AWS
  AdapterOverview type)
- ListAdapterVersions: remove Tags from summary, add FeatureTypes and
  StatusMessage (matches AWS AdapterVersionOverview type)
- AnalyzeDocument and StartDocumentAnalysis: return ValidationException
  when QUERIES is in FeatureTypes but QueriesConfig is absent or empty
- Update TestBatch2 and parity_a tests to reflect corrected AWS behavior
- Add parity_c_test.go with table tests for all three fixes

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

Executed-By: gopherstack/polecats/amber

* parity(timestreamwrite): database/table/write-records/batch-load accuracy + coverage

* parity(timestreamquery): accuracy + coverage

* parity(mediatailor): accuracy + coverage

* parity(accessanalyzer): accuracy + coverage

* parity(redshiftdata): accuracy + coverage

* parity(apigatewayv2): accuracy + coverage

* parity(elasticsearch): accuracy + coverage

* parity(kinesisanalyticsv2): accuracy + coverage

* parity(bedrockagent): accuracy + coverage

* parity(account): accuracy + coverage

* parity(rdsdata): accuracy + coverage

* parity(bedrockruntime): accuracy + coverage

* parity(sagemakerruntime): accuracy + coverage

* parity(iotdataplane): accuracy + coverage

* parity(apigatewaymanagementapi): accuracy + coverage

* parity(appconfigdata): accuracy + coverage

* fix(dashboard): update CreateHost call for codestarconnections VpcConfiguration+tags signature

* fix(ci): golangci-lint — refactor medialive Restore complexity, appstream goimports/shadow/naming, drop stale dashboard nolint

* fix(ci): unit test failures across folded services

* build(deps): bump actions/cache 5→6 (fold #2377)

* build(deps): make upgrade — go get -u ./... + go mod tidy

* fix(ci): UI svelte-check type + a11y errors across service pages

* fix(ci): restore kinesis page elements for ui-test (Create Data Stream, Total Streams card, placeholder)

* refactor(ctx): eliminate context.Background() from cloudformation/lambda/kms/secretsmanager production code — thread request/service ctx for clean cleanup

* fix(ci): integration regressions — CloudFront empty-time, S3Tables, IoT, CostExplorer, EMR, IoTAnalytics, AppMesh, DDB streams

* refactor(ctx): eliminate context.Background() batch 2 (iotanalytics/firehose/fis/dax/cloudwatchlogs/textract/stepfunctions/sns)

* fix(ci): lint + unit regressions from ctx refactor

* fix(ci): golangci-lint round 2 — refactor remaining complexity/format/naming issues

* refactor(ctx): eliminate remaining context.Background() from production code (batch 3)

* fix(ci): terraform shards 0/1/6/7 — align emulator responses with terraform-provider-aws

* fix(ci): lint + unit green after ctx refactor (gate both)

* fix(ci): integration shards 0/1/2 — align emulator wire shapes with AWS SDK

* fix(ci): e2e end-to-end SDK scenarios pass against emulator

* style(appmesh): goimports format parity_a_test.go

* fix(ci): e2e -tags=e2e compile/scenario errors from parity folds

* fix(e2e): kinesis dashboard CreateStream route + UI flow (fixes KinesisAnalyticsV2Dashboard test)

* feat(audit): deepen S3 (storage classes, range GET, copy, SSE) + DynamoDB (PartiQL, transactions, conditions) toward LocalStack parity

* feat(audit): deepen EC2 (Describe* filter matching, SG/VPC/ENI/EBS) + Lambda (invoke, ESM, layers, versions) toward LocalStack parity

* feat(audit): deepen IAM (policy eval, roles, instance profiles) + SQS (FIFO, DLQ, visibility, batch) toward LocalStack parity

* feat(audit): deepen SNS (fan-out delivery, filter policies, FIFO) + CloudFormation (intrinsics, real resource provisioning) toward LocalStack parity

* feat(audit): deepen RDS (instance/cluster lifecycle, snapshots, replicas, param groups) toward LocalStack parity

* test(rds): set ApplyImmediately=true so ModifyDBInstance class change applies now (matches AWS deferral semantics added in audit)

* feat(audit): back RDS Data API with a real in-memory SQL engine toward LocalStack parity

The RDS Data API previously executed no SQL: ExecuteStatement returned an
empty record set and ExecuteSql always reported 0 rows updated, so the
service modelled the control plane only. This closes the #1 functional gap
versus LocalStack (which runs a real database behind the Data API).

- Add services/rdsdata/engine.go: a pure-Go (modernc.org/sqlite, no cgo)
  per-(region, resourceARN) in-memory SQL engine. Each Aurora resource gets
  an isolated shared-cache database pinned by a keep-alive connection, scoped
  by an engine-instance nonce so two backends never alias the same store.
- ExecuteStatement / BatchExecuteStatement / ExecuteSql now run statements for
  real, returning genuine records, column metadata and update counts. Anything
  the engine rejects (e.g. DML against a table that was never created) degrades
  to the historical empty-success envelope, preserving backward compatibility.
- BeginTransaction opens a matching engine transaction; Commit/Rollback finalize
  it, giving real atomic visibility for statements tagged with a transactionId.
- Restore replays the recorded statement log so table state survives a
  snapshot/restore cycle (best-effort for parameterised/trimmed statements).
- README: correct the stale "image-based only" Lambda claim — Zip packaging
  across the managed runtimes is supported and already implemented.

Adds engine_test.go (round-trip, isolation, transactions, batch, snapshot
replay, reset, lenient fallback); package coverage 89.6%. Existing unit and
integration tests are unchanged and still pass.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GmKxLo2kS6qNWrTFuHhaEb

* feat(audit): deepen API Gateway (HTTP API routing, VTL, proxy integrations) + KMS (key lifecycle, grants, rotation) toward LocalStack parity

* test(terraform): RDS Data engine round-trip — create cluster, add data, query, destroy

Adds an `engine_roundtrip` case to TestTerraform_RDSData that provisions an
Aurora cluster via Terraform, then drives the full Data API data path against
it: CREATE TABLE, INSERT rows, and SELECT them back asserting the real
round-tripped values (long and string fields) plus column metadata. The
terraform harness tears the cluster down on cleanup, so the case covers
create-engine -> add-data -> query -> destroy end to end and exercises the new
in-memory SQL engine through the SDK + Terraform path.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GmKxLo2kS6qNWrTFuHhaEb

* feat(audit): deepen STS (AssumeRole variants, credential issuance, caller identity) + CloudWatch (metric aggregation, alarm state machine) toward LocalStack parity

* feat(rdsdata): bind named parameters in ExecuteStatement

ExecuteStatement previously dropped bound parameters — only the batch path
threaded them — so the common Aurora Data API pattern (e.g. `WHERE id = :id`)
fell back to the empty-result envelope. The backend method now accepts variadic
SQLParameters (keeping every existing call site source-compatible) and the
handler forwards req.Parameters, so named placeholders are substituted on both
the write and read paths.

Adds a parameterised round-trip test (insert with :id/:name, then select by :id).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GmKxLo2kS6qNWrTFuHhaEb

* feat(audit): deepen EventBridge (event-pattern matching, target delivery, scheduled rules) toward LocalStack parity

* fix(test): RDS FullLifecycle — set ApplyImmediately for the instance-class change

TestSDK_RDS_FullLifecycle modified DBInstanceClass without ApplyImmediately and
asserted the new class took effect immediately. Since RDS ModifyDBInstance was
deepened to defer instance-class changes to PendingModifiedValues (AWS-accurate
behaviour when ApplyImmediately is unset), the live class correctly stayed
unchanged and the assertion failed. The test now passes ApplyImmediately=true,
which is how a real client forces an immediate instance-class change. Pre-existing
failure on the parity-sweep base, unrelated to the rdsdata engine change;
surfaced by running CI for the first time.

Co-A…

v14.0.0

Toggle v14.0.0's commit message

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature.
parity: full 154-service deep-scan rewrite of parity.md (100% AWS-emu…

…lation audit) (#2339)

* parity: full 154-service deep-scan rewrite of parity.md

Rewrites parity.md as a complete per-service audit covering AWS-emulation
parity, performance, resource leaks, and UI/console coverage for every
service in services/. Includes a dedicated DynamoDB/DynamoDB Streams/DAX
deep dive (priority service) and a cross-cutting systemic-findings section
(non-opaque pagination, missing __type error envelopes, full-collection
sort-per-list, mock data-plane responses, unbounded maps, synchronous
lifecycles). Every finding is code-cited (file:line). Goal: 100% real AWS
emulation.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018oP7aXeXn2Eb1SL874KkPo

* parity: add region-isolation audit (DynamoDB + groups 2,3,6,8,9,11)

Adds a Region isolation audit section: per-service classification
(ISOLATED/PARTIAL/LEAKS/GLOBAL) of whether state is partitioned by region
and whether ops derive region from awsmeta.Region(ctx). Includes the
systemic flat-map/fixed-region-ARN finding and the fix pattern. Remaining
service groups to follow.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018oP7aXeXn2Eb1SL874KkPo

* parity: complete region-isolation audit for all 154 services

Replaces the partial region section with the full per-service
classification (ISOLATED / PARTIAL / LEAKS / GLOBAL) across all 20 service
groups. Tally: 49 ISOLATED, 25 PARTIAL, 60 LEAKS, 22 GLOBAL — confirming the
systemic finding that most backends use a flat name/ARN-keyed map with no
region dimension and build ARNs from a fixed default region. Each entry is
code-cited with the fix pattern; DynamoDB is the reference implementation.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018oP7aXeXn2Eb1SL874KkPo

* logging: context-aware logger everywhere; eliminate slog.Default()

Thread context through persistence so every record uses the context-aware
logger instead of the global default:

- persistence.Persistable now takes ctx: Snapshot(ctx)/Restore(ctx,data).
  The Manager holds a lifecycle baseCtx for the debounced async save path and
  tags each entry's logger worker=<service>-persistence; all manager logging
  goes through logger.Load(ctx) with *Context methods.
- Migrate all ~131 service Snapshot/Restore impls, interface assertions, call
  sites, and tests to the new signatures; replace every slog.Default() in
  service persistence with logger.Load(ctx).WarnContext(ctx, ...).
- Add logger.WithWorker(ctx, service, job) (records log as worker=<svc>-<job>),
  documented with the pointer-in-ctx safety rules (copy-on-write, derive from
  the lifecycle ctx, never enrich in a loop, never SetDefault at runtime).
- No context.Background() introduced: prod call sites use the request/root ctx,
  tests use t.Context().
- Enforce via golangci forbidigo (slog.Default()/slog.New() forbidden outside
  pkgs/logger) alongside the existing sloglint no-global/context settings.
- Document the logging discipline in AGENTS.md.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018oP7aXeXn2Eb1SL874KkPo

* logging: tag background workers + remove DAX embedded logger

- Add worker=<service>-<job> tagging at the background-worker boundary:
  startBackgroundWorkers wraps each worker ctx via logger.WithWorker, and the
  auto-purge worker logs under worker=purge-worker.
- DAX data plane: drop the embedded *slog.Logger field on Server; store a
  lifecycle baseCtx tagged worker=dax-dataplane and log via logger.Load(ctx).
  NewServer/EnableDataPlane/newDataPlane now take context.Context (sourced from
  the provider JanitorCtx) instead of a *slog.Logger.
- Add a -race copy-on-write test (pkgs/logger) proving concurrent
  WithService/WithWorker/AddAttrs derivation never mutates the shared parent
  logger or leaks child attributes upward.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018oP7aXeXn2Eb1SL874KkPo

* persistence: centralise snapshot marshal/unmarshal via ctx-aware helpers

Add persistence.MarshalSnapshot / UnmarshalSnapshot and safemap.ClonePtrMap /
CloneRegionalPtrMap, then migrate every service backend's Snapshot/Restore to
the shared helpers. The helpers emit a DebugContext record on success (silent at
the default info level, visible with --log-level debug) and a WarnContext on
failure, which gives the previously-unused ctx parameter a purpose.

This clears the 188 revive "unused-parameter ctx" findings and the stepfunctions
sloglint finding structurally, rather than per-method, and removes ~110 lines of
hand-rolled marshal/error/log boilerplate net.

Also fixes the remaining lint blockers on the branch:
- cli.go startPurgeWorker: drop the overwritten log param (staticcheck SA4009)
- dax tests: context.TODO() instead of nil Context (staticcheck SA1012)
- cli_test / opensearch test: add t.Helper() (thelper)
- appstream Restore: move //nolint to the func line; lll/golines/nolint cleanups
- gofmt/golines formatting on lambda & stepfunctions settings

golangci-lint run ./...: 0 issues. go test ./... -short: pass.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018oP7aXeXn2Eb1SL874KkPo

* chore: remove broken AI release-notes tooling (pkgs/releaser)

The AI release-notes generator (Gemini/Copilot) was broken and unused — nothing
in the repository imported it. Remove the package and unwire it:

- delete pkgs/releaser (incl. cmd/releaser)
- drop its sole dependency github.com/github/copilot-sdk/go (and the now-unused
  transitive github.com/google/jsonschema-go) via go mod tidy
- remove the build-releaser Makefile target
- prune the AI release-notes steps (use_ai_releaser input, COPILOT_TOKEN env,
  Build Releaser / Install Copilot CLI / Generate Release Notes) from the release
  workflow; GoReleaser now runs with plain `release --clean`

The rest of the release pipeline (tagging, GoReleaser, GHCR, cleanup) is intact.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018oP7aXeXn2Eb1SL874KkPo

* awserr: add protocol-aware APIError/Classify/Write responder (Phase 2)

Extend pkgs/awserr beyond sentinels into a single AWS-error responder so
services can declare a map[error]APIError table and emit the correct wire
envelope (JSON 1.0/1.1, Query-XML, REST-XML) via one call instead of
hand-rolling __type/<Error> serialisation + CRC32 headers per service.

- APIError{Code,Message,HTTPStatus} protocol-agnostic error description
- Classify(err, table, fallback) matches wrapped sentinels via errors.Is
- Write(c, proto, e) serialises the per-protocol envelope + Content-Type

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018oP7aXeXn2Eb1SL874KkPo

* stepfunctions: use x/sync semaphore.Weighted for parallel/map limits (Phase 3)

Promote golang.org/x/sync to a direct dependency and replace the hand-rolled
chan struct{} semaphores in the ASL executor's Parallel and Map state fan-outs
with semaphore.Weighted. Both sites already did a blocking, ctx-aware acquire
(select on send vs ctx.Done), which Acquire(ctx, 1) expresses directly and more
readably with identical semantics. Other concurrency sites (background pollers
with non-blocking try-acquire, lifecycle WaitGroups) are intentionally left as
-is since x/sync adds nothing there.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018oP7aXeXn2Eb1SL874KkPo

* dax,testleak: bound DAX attr dictionary + add goleak detection (Phase 4)

Leak prevention:
- Bound the DAX data-plane attribute-list dictionary (attrToID/idToAttr) with a
  hard cap. Eviction is unsafe because a client may reference any previously
  -assigned id, so on overflow the server stops allocating and degrades to the
  empty-list id instead of growing without limit. Legitimate workloads register
  only a handful of distinct attribute sets, so the cap is never hit in practice.
- Add pkgs/testleak wrapping go.uber.org/goleak (promoted to a direct dep) with
  a shared ignore list, and opt in worker-heavy packages whose tests already
  clean up: dax/dataplane, scheduler, pipes, s3, dynamodb. goleak surfaced
  genuine pre-existing test-hygiene leaks in sqs/lambda/stepfunctions (backends
  constructed without Close); those packages are left for a focused follow-up
  rather than shipping red CI.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018oP7aXeXn2Eb1SL874KkPo

* collections: add generic Filter/Map/Values/SortedKeys helpers (Phase 6)

Add pkgs/collections with the type-safe slice/map transformation helpers the
stdlib slices/maps packages don't provide (Map, Filter, MapValues, Values,
SortedKeys), to replace the hand-rolled range-and-append list-builders repeated
across handlers. A reflect-free generic DeepClone was evaluated and dropped: a
correct deep copy of arbitrary pointer/slice-containing types is not possible
without reflection or codegen, and safemap.ClonePtrMap already covers the
snapshot copy path.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018oP7aXeXn2Eb1SL874KkPo

* worker: add leak-safe ticker primitive for janitors (Phase 7)

Add pkgs/worker.RunTicker, a single owner of the background-sweep loop that ~30
service janitors hand-roll (time.NewTicker + defer Stop + ctx.Done select). It
applies the standard worker logging tags, optionally bounds each sweep with a
timeout, and always stops the ticker on return so the loop cannot leak. Adopt it
in the sqs and acm janitors as references.

pkgs/httpclient and pkgs/lifecycle from the plan were evaluated and dropped:
every HTTP client in the tree already sets a tuned per-service timeout (nothing
uses http.Get/DefaultClient/bare http.Client{}), and a central goroutine
supervisor would require rewiring every janitor/go func — too invasive to do
safely here, with worker + goleak already covering leak-safety incrementally.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018oP7aXeXn2Eb1SL874KkPo

* awstest: add shared handler-test harness (Phase 5, Tier A)

Add internal/awstest with NewContext/NewJSONContext/DecodeJSON to collapse the
echo.New() + httptest.NewRequest + recorder + NewContext wiring repeated across
300+ handler test files. Adopt it in the account service's test helper as a
reference. Production code is untouched, so there is zero protocol-parity risk.

Note on Phase 2/awserr fan-out: blanket migration of the 67 hand-rolled error
tables is intentionally deferred. The error envelopes are heterogeneous
(dynamodb carries extra Item/CancellationReasons fields, REST services use plain
application/json without CRC32), so a generic responder cannot replace them
without per-service fidelity loss. awserr.Write remains available and tested for
services whose envelope matches one of its protocols.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018oP7aXeXn2Eb1SL874KkPo

* stepfunctions: enable goleak detection (Phase 4 follow-up)

Add a goleak TestMain to the stepfunctions package and stop the two SQS
integration backends its tests construct (t.Cleanup(sqsBackend.Close)), which
goleak flagged as leaked runJanitor goroutines. No production changes; no
goroutine-ignore escapes needed.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018oP7aXeXn2Eb1SL874KkPo

* services: adopt worker.RunTicker in 4 more janitors (Phase 7)

Convert the bedrock, eventbridge, support and timestreamwrite janitors — whose
run loops were the exact ticker + ctx.Done + single-sweep shape — to
worker.RunTicker, matching the sqs/acm references. The sweep ctx now carries the
worker logging tags. Other janitors with multi-statement tick branches, extra
select cases, or stop-channel patterns were intentionally left unchanged.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018oP7aXeXn2Eb1SL874KkPo

* sqs: stop move tasks on Close + enable goleak detection (Phase 4 follow-up)

Production fix: Close() now cancels in-flight StartMessageMoveTask goroutines
(via each move task's stored cancel func) in addition to stopping the janitor,
so no background goroutine outlives the backend. goleak flagged both runJanitor
and runMoveTask as leaking.

Tests: add a goleak TestMain and route every backend construction through a
t.Cleanup(b.Close) (constructor helpers gained a *testing.T param; inline
NewHandler(NewInMemoryBackend()) sites were extracted to a cleaned-up var). No
assertions changed; no goroutine-ignore escapes needed.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018oP7aXeXn2Eb1SL874KkPo

* lambda: tie async invocations to backend lifecycle + enable goleak (Phase 4 follow-up)

Production fix: async (Event) invocation goroutines spawned by
enqueueAsyncInvocation were detached and could block in waitForAsyncResult for
up to timeout+grace with nothing tied to shutdown. Add a shutdown channel +
asyncWG: the spawn sites run via asyncWG.Go, waitForAsyncResult selects on
shutdown, and Close() closes the channel (once) and waits for the group after
shutting down the function-URL/runtime servers. goleak confirmed the leak.

Tests: add a goleak TestMain and a closeBackend(t, b) helper; route all
NewInMemoryBackend sites through t.Cleanup(b.Close). No goroutine-ignore escapes.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018oP7aXeXn2Eb1SL874KkPo

* services: replace hand-rolled pointer-deref helpers with pkgs/ptrconv

dms, dynamodb and resourcegroupstaggingapi each defined private *string/*bool
deref helpers (ptrStr/ptrBool/derefStr/derefOrEmpty/ptrStringValue) with
semantics identical to ptrconv.String/Bool. Route all call sites through ptrconv
and delete the duplicates (dms.ptrStr alone had 131 callers).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018oP7aXeXn2Eb1SL874KkPo

* s3: replace nilStringIfEmpty with pkgs/ptrconv.NilIfEmpty

The private nilStringIfEmpty helper was identical to ptrconv.NilIfEmpty (empty
string -> nil, else pointer). Route all 19 call sites through ptrconv and remove
the duplicate.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018oP7aXeXn2Eb1SL874KkPo

* awserr: use canonical X-Amzn-Requestid header literal

The canonicalheader linter flagged the non-canonical "x-amzn-RequestId" literal
in requestID(). Header.Get is case-insensitive so behaviour is unchanged; this
matches the canonical form already used in glacier/apigateway.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018oP7aXeXn2Eb1SL874KkPo

* services: adopt collections.SortedKeys for the sort-map-keys idiom (Phase 6)

Replace the hand-rolled `keys := make([]T,0,len(m)); for k := range m {
keys=append(keys,k) }; sort.Strings(keys)` idiom with a single
collections.SortedKeys(m) call across 80 service files.

Also harden the helper: SortedKeys now always returns a non-nil slice (empty for
a nil/empty map), faithfully matching the idiom it replaces, so callers that
marshal the result emit a JSON array rather than null. This fixes a codecommit
regression (ListAssociatedApprovalRuleTemplatesForRepository returning null for
an empty template set) and keeps all call sites behaviour-identical.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018oP7aXeXn2Eb1SL874KkPo

* worker: make pkgs/worker the resilient background-work standard

Enrich the worker primitive so all background work is panic-resilient and has
uniform start/stop/timer hooks:
- RunTicker now recovers from sweep panics (logged with worker tags, loop
  continues) — all existing adopters get resilience with no call-site change.
- Add functional options (WithImmediate, WithOnPanic) so janitor variants are
  absorbed by the primitive rather than hand-rolled.
- Add RunTickerN for janitors with multiple independent tickers.
- Add Group: a per-backend supervisor bundling tracked goroutines (Go),
  periodic sweeps (Ticker), and one-shot cancellable timers (After) under one
  panic-recovered lifecycle, with a deterministic Stop that cancels, stops
  pending timers, and joins — the standard replacement for raw time.AfterFunc
  and untracked `go func` that outlive a backend.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018oP7aXeXn2Eb1SL874KkPo

* eks,transfer,autoscaling,acm: stop background timers on shutdown (leak fix)

These backends scheduled delayed state transitions / hook expiries with raw
time.AfterFunc but never stopped them, so the timer goroutines (and their
backend-capturing closures) outlived teardown.

- eks, transfer: had no Close at all. Route the state-transition timers through
  a per-backend worker.Group (panic-recovered) and add Close()->work.Stop(),
  invoked from a new handler Shutdown (service.Shutdowner, called at server
  shutdown via cli.go).
- autoscaling: add a defensive Close() that stops any in-flight lifecycle-hook
  expiry timers, wired into a new handler Shutdown.
- acm: add Close() that stops all in-flight auto-validation timers and call it
  from the existing handler Shutdown (previously only the janitor was stopped).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018oP7aXeXn2Eb1SL874KkPo

* service: add AccountRegion helper to collapse provider config boilerplate

~140 service providers repeat the same config.Provider type-assertion to pull
account ID and region off the AppContext. AccountRegion centralises it with the
exact same empty-fallback behaviour, ready for fan-out adoption.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018oP7aXeXn2Eb1SL874KkPo

* comprehend,timestreamquery: hoist fixed regexes to package level

These compiled the same fixed regex on every call: comprehend recompiled the
email/SSN PII patterns per DetectPiiEntities/ContainsPIIEntities request (hot
path), and timestreamquery recompiled the rate() schedule regex on every
next/previousInvocationTime call. Hoist them to package-level vars compiled once
at init. User-supplied/dynamic patterns (cloudwatchlogs query terms, macie2
custom-identifier regex) are intentionally left compiled at call time.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018oP7aXeXn2Eb1SL874KkPo

* service: add AccountRegionOrDefault for the default-seeded provider idiom

The empty-fallback AccountRegion only fits providers that intentionally leave
account/region empty when unconfigured. The dominant provider idiom instead
seeds config.DefaultAccountID/DefaultRegion and overwrites from config.Provider.
AccountRegionOrDefault matches that exactly so ~110 providers can collapse the
block without changing the no-config fallback.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018oP7aXeXn2Eb1SL874KkPo

* services: adopt service.AccountRegion(OrDefault) across 100 providers

Collapse the repeated config.Provider account/region extraction block in
provider.go into a single helper call: ec2/lambda use AccountRegion (empty
fallback), and 98 default-seeded providers use AccountRegionOrDefault (which
falls back to config.DefaultAccountID/DefaultRegion). Behaviour-preserving;
providers with extra GlobalConfig reads, nil-ctx wraps, per-branch backend
construction, or non-default fallbacks were left untouched.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018oP7aXeXn2Eb1SL874KkPo

* worker: fix data race in Group.After timer tracking

The `var t *time.Timer; t = time.AfterFunc(d, func(){ ...uses t... })` pattern
let the fired callback read t while the scheduling goroutine wrote it (-race
flagged it via eks/transfer state-transition tests). Track timers by an
integer id captured before scheduling instead, so the callback never reads the
timer pointer it is stored under.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018oP7aXeXn2Eb1SL874KkPo

* services: migrate 27 janitors to worker.RunTicker/RunTickerN

Replace the remaining hand-rolled time.NewTicker janitor loops with the worker
primitives, standardising on panic-recovered, leak-safe background sweeps:
- single-sweep janitors (with per-sweep TaskTimeout) -> worker.RunTicker
- multi-ticker janitors (cloudwatch metric+alarm, dynamodb table+TTL) ->
  worker.RunTickerN with one Sweep per cadence
Hand-rolled recover() blocks (s3, dynamodb) are dropped since RunTicker now
recovers centrally; all telemetry (RecordWorkerTask/Items) and sweep logic is
preserved. No hand-rolled janitor ticker loops remain.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018oP7aXeXn2Eb1SL874KkPo

* services: adopt arn.Build for hand-rolled ARNs (66 files)

Replace fmt.Sprintf("arn:aws:...") ARN construction with pkgs/arn.Build /
BuildS3 across services, deriving the partition centrally and covering the
global (empty-region) and iam/s3 special forms. Behaviour-preserving: every
converted ARN is byte-identical (verified by the services' existing ARN
assertions). Sites with a local variable named `arn` had that local renamed
(arnStr/fnARN/planARN) to avoid shadowing the package; shapes not expressible
by arn.Build (e.g. macie2's iam service-linked-role ARN) were left untouched.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018oP7aXeXn2Eb1SL874KkPo

* eks,autoscaling,transfer: add goleak TestMain to guard timer leaks

With state-transition/hook timers now stopped via Close (worker.Group / timer
cleanup), add a goleak TestMain to each so any future background-goroutine leak
(an unstopped timer, a new janitor without shutdown) fails the suite. No test
cleanup rollout was needed — the suites already leave no goroutines running.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018oP7aXeXn2Eb1SL874KkPo

* worker: root Group at the service context + own logging/metrics

Redesign worker.Group so background work is service-context-rooted and the
package owns the cross-cutting concerns:
- NewGroup(ctx, service, opts...) derives from the service/lifecycle context
  (no more context.Background); it always logs via the context logger.
- Inject a Metrics sink (WithMetrics, default pkgs/telemetry-backed) so the
  worker auto-emits per-sweep task status (success/panic) and tests can fake it.
- Group.Ticker is now the self-contained periodic primitive (recovery +
  per-sweep timeout + WithImmediate); After/Go/Stop unchanged in spirit.

Thread the service context through the eks and transfer backend constructors
(NewInMemoryBackend(ctx, ...)) — providers pass JanitorCtx, tests pass
t.Context(), and internal/teststack threads it via the handlers struct. No
context.Background() outside the service-context initialization.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018oP7aXeXn2Eb1SL874KkPo

* worker: Group records only the panic task, leaving sweep telemetry intact

Janitors emit success/items/depth telemetry at a finer granularity than the
ticker that drives them, so auto-emitting a per-ticker "success" would
double-count or coarsen it. Group now records only the "panic" task (the failure
a sweep cannot catch) via the injected Metrics; sweeps keep their own telemetry.
Metrics is narrowed to RecordTask.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018oP7aXeXn2Eb1SL874KkPo

* services: standardize all janitors on worker.Group; drop RunTicker/RunTickerN

Convert all 32 remaining janitors from worker.RunTicker/RunTickerN to the
worker.Group pattern: Run(ctx) creates a service-context-rooted Group, registers
its sweeps via g.Ticker (multi-ticker janitors register several), blocks on
ctx.Done, then g.Stop()s — preserving the existing StartWorker/cancel lifecycle
while routing every background worker through one resilient, panic-recovering,
service-context-rooted primitive. mediaconvert's fire-and-forget StartJanitor and
cloudwatch/dynamodb's multi-ticker loops are expressed as Group registrations.

With no callers left, RunTicker, RunTickerN and the Sweep type are removed.

Also thread the service context through the remaining external callers of the
eks/transfer constructors: the cloudformation phase3-6 test-backend helper chain
(gaining a *testing.T) and internal/teststack.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018oP7aXeXn2Eb1SL874KkPo

---------

Co-authored-by: Claude <noreply@anthropic.com>

v11.2.0

Toggle v11.2.0's commit message

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature.
missing copilot (#953)

v11.1.0

Toggle v11.1.0's commit message

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature.
try releaser (#952)

* try releaser

* lint

v4.0.0

Toggle v4.0.0's commit message

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature.
retcon (#65)

v3.3.0

Toggle v3.3.0's commit message

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature.
Release fix (#37)

* Update .goreleaser.yml

* Update .goreleaser.yml

v3.2.0

Toggle v3.2.0's commit message

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature.
Update .goreleaser.yml (#36)

v3.1.0

Toggle v3.1.0's commit message

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature.
fix (#35)

v2.0.0

Toggle v2.0.0's commit message

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature.
badges (#33)

v1.0.17

Toggle v1.0.17's commit message

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature.
sort (#31)

* sort

* update badge .badges/31/merge/coverage.svg

* commit

---------

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>