Queue: snapshot data-loss revert, three accepted-then-ignored params, and a diff-scoped lint gate - #2417
Queue: snapshot data-loss revert, three accepted-then-ignored params, and a diff-scoped lint gate#2417agbishop wants to merge 259 commits into
Conversation
|
Important Review skippedDraft detected. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Plus Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Codecov Report❌ Patch coverage is 📢 Thoughts on this report? Let us know! |
📊 Code Coverage Report
Tip This project maintains a minimum coverage threshold of 85%. Maintain or improve coverage on new code to ensure long-term stability. Last updated: Tue, 11 Aug 2026 21:26:21 GMT |
…Image against images that do not exist The siblings left out of 973aa01. Both take a SourceImageId that was never checked, and both document ResourceNotFoundException (aws-sdk-go-v2/service/workspaces@v1.73.1 deserializers.go:772 and :1636). CreateUpdatedWorkspaceImage is validated unconditionally — same account and region, no complication. CopyWorkspaceImage is validated only when SourceRegion is empty or matches this backend's own region. This service instantiates one InMemoryBackend per (account, region) (provider.go:26-28), b.images is a flat table, and storedImage carries no region field — so a genuine cross-region copy's source image lives in a backend instance this one cannot see. Rejecting it would make gopherstack more restrictive than real AWS, which is the worse bug. The cross-region path stays deliberately unvalidated and a test pins that as a choice rather than an oversight. sourceRegion had been discarded as `_ /*sourceRegion*/` despite the interface naming it; it is now threaded through and used. Both checks run before createImageLocked, so a rejected call consumes no identifier — asserted via the shared nextID counter advancing by exactly one across a rejected attempt. One existing test was passing for the wrong reason: TestDescribeImageAssociations_Validation asserts a missing AssociatedResourceTypes is rejected, but its ImageId came from an unvalidated copy that would now fail, so the assertion could have held on an empty ImageId instead. It creates a real source image first. Closes gopherstack-plmb Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…ot a bare identifier
entryLineRe required `[A-Za-z0-9_]+` for the key, but real family keys name
several operations at once or carry a parenthetical — AddPermission/RemovePermission,
Database/TableMetadata (Get/List), Create/UpdateConfigurationTemplate response
shape. Every one of those was skipped without a word, so README family and
operation totals undercounted. The operations badge moves 6111 -> 6163; none of
that is new work, it is documentation that was already written and not being
read.
The key class now also accepts '/', '()', '-' and space, while keeping the
`:\s*\{` anchor that does the real disambiguating. Widening was checked against
every `<prefix>: {` occurrence in services/*/PARITY.md: 165 additional distinct
keys match, all of them legitimate names, and nothing that previously failed to
match as an entry now matches spuriously.
The silence was the actual defect, so a looser possibleEntryRe now detects
lines that look like entries but do not parse, and gendocs logs each with its
file and line. Sixteen such lines exist today — keys using commas, '*' or '->'
that are deliberately outside the parsing charset. They were invisible before
and are now reported on every run.
Warnings are non-fatal on purpose. ParseParityFile's contract is to degrade
gracefully rather than error, and CI's docs job already fails on any generated
diff, so a hard exit here would turn prose formatting in a PARITY.md note into
a blocking gate.
Closes gopherstack-udc7
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
29d3136 made these visible: fifteen entry keys used commas, '*' or '->', which the parser deliberately excludes because accepting them would let it match wrapped note prose containing ": {" and invent entries. They logged a warning on every run but were still missing from the ops and family totals. Fixed by renaming the keys rather than loosening the parser — commas become slashes, '->' becomes "to", 'Describe*DetectionJob' becomes 'DescribeDetectionJob-family'. Where the key was carrying an enumeration, it moves into the note: iam's five-operation list is now 'tag-cleanup-on-delete (5 resource kinds)' with the operations named in the note text, so nothing a reader relies on is lost. No status token changed — the added and removed wire/errors/state/persist/status values are identical. This is a naming change only. Fourteen of the sixteen warnings are gone. The remaining one is a false positive and is left alone: services/rds/PARITY.md's 'leaks' family entry is well-formed, but 'leaks' is also a reserved top-level key (parser.go:57), so matchEntry rejects it and warnUnparsedEntry reports it. Filed separately. Closes gopherstack-42va Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
… was run The 2026-07-25 audit diffed against v1.51.11 while go.mod pins v1.56.4, so "every wired field diffed" was true of the wrong SDK. Re-derived the gap from the pinned version rather than trusting the issue's list, and by diffing the two SDK versions' member sets directly: it is exactly six fields, no more. Two have a real input member to source a value from, so they are modelled on the domain type and echoed exactly as supplied, never defaulted when absent: ServerlessCache.NetworkType (CreateServerlessCacheInput.NetworkType, serializers.go:6709 — create-only, no Modify member) and ReplicationGroup.Durability (Create serializers.go:6506, Modify :8171). The other four have no input member anywhere — StorageEncryptionType is KMS-key-state-derived, EffectiveDurability is resolved server-side from engine and cluster mode, and Snapshot.Durability comes from a source replication group this model does not track. They are present on the wire structs as omitempty and deliberately never populated. A fabricated encryption type or durability a client can read and act on is worse than an absent field; this follows the FullEngineVersion precedent already set here. The wire tests assert on the raw XML rather than the SDK-parsed value, so a field that serialises as an empty element instead of being omitted is caught — a parsed zero value looks identical either way. elasticacheSnapshotVersion stays at 1. Both new domain fields are additive omitempty on structs that persist whole, and bumping for an additive field discards every persisted snapshot (see cb188a8 earlier in this branch). Closes gopherstack-31dm Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…ticache fields Operations badge 6163 -> 6169: fourteen family entries that the parser was skipping on a key-charset technicality now count, plus the elasticache additions. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…guration The audit that claimed CreateScheduledQuery and GetScheduledQuery modelled the full DestinationConfiguration was run against v1.80.0 while go.mod pins v1.81.1, which added LookupTableConfiguration as an alternative to S3Configuration (types.go:778, type at :1561). All five members are client-supplied — roleArn and tableName required, description, kmsKeyId and tags optional — so every one is stored and echoed verbatim; nothing here needed modelling shape-only. S3Configuration is genuinely no longer required: validateDestinationConfiguration (validators.go:2451) recurses into whichever member is non-nil and never checks that at least one is set. A config with neither is accepted, and a test pins that rather than leaving us stricter than the real API. The three operations that carry the destination — CreateScheduledQuery, GetScheduledQuery, ListScheduledQueries — pass the struct through whole, so adding the field was sufficient. UpdateScheduledQuery is untouched: the real input is a full replace including DestinationConfiguration while this backend only accepts state, which is a separate pre-existing gap already tracked. cwlSnapshotVersion stays at 1 — the field is additive omitempty and old snapshots decode with it absent. Closes gopherstack-09o8 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…er the audit Both audits ran against a stale sdk_module pin, so "every wired field diffed" was true of the wrong SDK. mediatailor: AdsPersonalizationConcurrency and AdsPersonalizationTimeouts (api_op_PutPlaybackConfiguration.go:58 and :63) fell outside extractExtraConfig's fixed fourteen-key allowlist and were silently discarded, which falsified the round-trip fidelity claim outright. Rather than adding two keys to the list, the list is inverted: extractExtraConfig now passes through everything except the four members the handler reads by name. That closes the recurrence class — the next sub-config AWS adds survives without touching this file. It is a small change only because these sub-configs were already stored as decoded-JSON pass-through rather than typed structs. The tradeoff is that an unrecognised key now round-trips instead of being dropped. Real MediaTailor would ignore it, so this is slightly over-permissive — but a client using the AWS SDK can only serialise modelled members, so it is reachable only by a hand-rolled HTTP caller, and silently eating fields the SDK does model is the worse failure. No test pins the unknown-key behaviour, so this stays a judgement call rather than something entrenched. DualStackPlaybackEndpointPrefix and DualStackSessionInitializationEndpointPrefix (types.go:1049,1053) are response-only with no input member. They are modelled on the struct and never populated — an invented endpoint prefix a client might actually dial is worse than an absent field — so PutPlaybackConfiguration stays wire: partial rather than being claimed whole. mediaconvert: MaximumConcurrentFeeds (api_op_CreateQueue.go:47) is threaded through Create and Update. No equivalent mechanism fix applies there — createQueueInput and updateQueueInput are hand-modelled typed structs, so every accepted field must be declared and there is no allowlist to invert. Neither snapshot version constant is bumped; both stay at 1. Refs gopherstack-gt9o Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…aconvert parity updates Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…eserved word services/rds/PARITY.md has both a genuine top-level `leaks:` section at column 0 and an indented `leaks:` family entry. matchEntry rejected any line whose key was reserved regardless of indent, while isBlockTerminator only accepts a match at column 0 — so the indented entry fell through both, counted as neither, and was dropped from the families total. Since 29d3136 it also produced a warning on every run, about a line that is not malformed. matchEntry now rejects a line only when isBlockTerminator would claim it. That ties the two functions together by construction, so no line can fall through both, and it generalises: the same collision was waiting for any service naming a family `gaps`, `protocol` or `gaps`-adjacent. Indentation is the only workable discriminator here. The obvious alternative — that a section header carries no brace on its own line — is false: rds's real `leaks:` header is written `leaks: {status: ..., note: "..."}`, brace-identical to a family entry. A 0-space entry whose key is reserved is still read as that key's section header. At column 0 the two forms are genuinely indistinguishable, and parseFrontmatter re-reads the line as the scalar field, so the content becomes LeaksStatus rather than being lost. The existing tolerance for 0-space entries with non-reserved keys (services/mwaa, services/rekognition) is unaffected — isReservedKey never applied to those. Families across all 159 PARITY.md files go 1016 -> 1017, and the false warning count goes 1 -> 0. Closes gopherstack-jw5s Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…difyClientProperties wiping the others Continues the stale-pin sweep. Both services were audited against an older SDK than go.mod pins — the cache still holds ssoadmin@v1.38.0 and workspaces@v1.68.3 alongside the pinned v1.43.1 and v1.73.1, and the fields in question do not exist in the older ones. The workspaces half turned up a bug the issue did not mention: ModifyClientProperties replaced the whole stored struct on every call, so setting one property silently cleared every other. The real operation is a partial update. It now merges, leaving an omitted field at its previous value. ClientExperiencePolicy (types.go:269) and LogUploadEnabled (:275) are both threaded; the latter was unwired too. ClientExperiencePolicy is deliberately unvalidated: unlike its neighbours LogUploadEnabled and ReconnectEnabled, which have generated enum types with Values(), it is a bare *string with no @enum trait. The FORCE_CLASSIC/FORCE_UI_2026/USER_CHOICE values in its doc comment are illustrative, so rejecting anything else would be stricter than AWS. ssoadmin: PermissionSetsEnabled (api_op_DescribeInstance.go:77) is stored as a *bool, so an instance that never set it stays nil and is omitted rather than reported as a fabricated false. AWS documents that it cannot be disabled once enabled, but that is prose rather than an SDK-pinned constraint, so both values are accepted verbatim. InstanceMetadata.Regions is populated from real AddRegion state via ListRegions. PrimaryRegion is modelled shape-only and never set: nothing in this backend can source it, since RegionMetadata.IsPrimaryRegion is always false here. Neither snapshot version constant is touched — workspaces stays 1, ssoadmin stays 2. workspaces' clientProperties map is pre-existing ephemeral state that was never in backendSnapshot, so the new fields inherit that gap rather than creating one. A round-trip test was written, confirmed to fail against that pre-existing non-persistence, and reverted rather than expanding scope; recorded in PARITY.md instead. Refs gopherstack-gt9o Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…oadmin/workspaces fields rds picks up its 'leaks' family row, which the parser had been dropping on a reserved-word collision. Operations badge 6169 -> 6172. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Both fields arrived in the SDK after this service was audited (types.go:52 and
:550 at the pinned v1.53.5) and were silently omitted from every response.
Unlike most of this sweep these are not caller-supplied — they are derived from
the org tree gopherstack already models, so leaving them unset would have been
the wrong answer. Getting the format wrong would be worse than omitting them
though, and the Go doc comments pin nothing ("The paths in the organization
where the account exists"), so the format comes from the AWS API Reference
example responses and the published regex, cited in buildPath's comment:
o-<org>/r-<root>/(ou-<id>/)*<ownID>/ — org, root, ancestor OUs top-down, the
resource's own id, trailing slash.
Paths is plural but Organizations is a strict single-parent tree — moving an
account between roots is an error, MoveAccount takes one source and one
destination, and this backend stores a single accountParent. It therefore
always returns exactly one path and never fabricates a second.
Populated on the seven operations that actually return these types, found by
searching for the types rather than trusting the gap note: DescribeAccount,
ListAccounts, ListAccountsForParent, DescribeOrganizationalUnit,
UpdateOrganizationalUnit, ListOrganizationalUnitsForParent and
CreateOrganizationalUnit. ListChildren and ListParents are excluded because
they return summary types that carry no path in real AWS.
The ancestor walk is bounded, so a cyclic or dangling parent chain cannot spin:
it returns no path at all rather than a partial or invented one. That state is
unreachable through the API and only constructible via a corrupted snapshot,
which is how the test builds it.
Nothing new is persisted. Both fields are json:"-" and computed at read time
from state that was already stored, so organizationsSnapshotVersion stays at 1.
Refs gopherstack-gt9o
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
NetworkType arrived after this service was audited and was dropped end to end — absent from the inputs, never echoed, error not in the lookup table. DBCluster.NetworkType (types.go:236) is settable on CreateDBCluster (api_op_CreateDBCluster.go:171) and ModifyDBCluster (:136), so it is accepted, stored and echoed. It defaults to IPV4 because the SDK documents that as the default in as many words — "IPV4 – ( the default )" — not because a default seemed reasonable. DBInstance.NetworkType (types.go:764) has no input member on either CreateDBInstance or ModifyDBInstance; the SDK says it is inherited from the DB cluster, so that is where this takes it from rather than inventing an option the API does not offer. NetworkType is a bare *string with no entry in types/enums.go, so any value is accepted. Restricting it to IPV4/DUAL would be stricter than the real API. Two things are deliberately left inert, and both would have been easy to fake: SupportedNetworkTypes on DBSubnetGroup (types.go:945) and OrderableDBInstanceOption (types.go:1291) is modelled on the wire in its real member-wrapped list shape but never populated. Subnets here are opaque ID strings with no CIDR data, and the orderable-options catalog is static, so there is no honest basis to say which network types are supported. A fabricated capability list is worse than an absent one, and a test asserts it is genuinely absent from the XML rather than present and empty. NetworkTypeNotSupportedFault (errors.go:1417) is not added to the error lookup table. Real Neptune raises it when a requested network type conflicts with the subnet group's actual CIDR support — a condition this backend cannot detect. Inventing a rejection so the error had something to raise would be the more-restrictive-than-AWS bug class. neptuneSnapshotVersion stays at 1; the new fields are additive omitempty. Refs gopherstack-gt9o Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…ates Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…berately never populated The field arrived after this service was audited (types.go:803, :969, :6079 at the pinned v1.73.4) and was missing from GetAutomationExecution, DescribeAutomationExecutions and DescribeAutomationStepExecutions. It is modelled and left permanently unset, which is the honest outcome rather than a shortcut. Real SSM sets it when its engine detects a non-critical issue mid-run; StepExecution's doc adds "Present only if the step status includes a warning". There is no such status in the enum, so it is engine-detected, not a modelled transition. This backend has nothing to detect: completeAutomationLocked drives every step to Success unconditionally, and automationStatusFailed is declared in store.go but never assigned anywhere — there is no failure, timeout, retry or degraded path to report a warning from. Inventing a warning string would put text in front of an operator that no real condition produced. Same call as apigatewayv2's failOnWarnings on this branch, which is validated but documented as inert because the emulator generates no import warnings. The test asserts the field is genuinely absent from the raw response body, not merely empty when parsed — those are indistinguishable through the SDK, and omitempty is the only thing separating them. ssmSnapshotVersion stays at 1. Refs gopherstack-gt9o Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…PC config Both fields arrived after this service was audited and were read nowhere. Connector.IpAddressType (types.go:720) is set by CreateConnector (api_op_CreateConnector.go:86) and UpdateConnector (:80), and echoed on DescribeConnector. WebAppVpcConfig (:2745) and UpdateWebAppVpcConfig (:2648) carry their own, set through Create/UpdateWebApp's EndpointDetails. Two absences here are real AWS behaviour and are deliberately preserved, with tests pinning them so a later pass does not "fix" them into existence: DescribedWebAppVpcConfig (types.go:1417) has no IpAddressType and no deserializer case for one, so a client sets it and cannot read it back. The describe output is untouched. This is the same asymmetry PARITY.md already records for SecurityGroupIds. ListedConnector (types.go:1897) carries only Arn, ConnectorId and Url, so ListConnectors keeps omitting the field. Neither enum is validated. Both are IPV4/DUALSTACK, but the sibling Server.IPAddressType — the same enum shape — is threaded through servers.go with no validation, while EndpointType, Domain and TLSSessionResumptionMode in that same file do validate. Following the established local precedent for this exact shape rather than inventing strictness AWS may not have. The web-app value is stored despite never being echoed: it round-trips through Snapshot/Restore and is readable from the backend struct, matching how SecurityGroupIDs is already handled here. transferSnapshotVersion stays at 1. Refs gopherstack-gt9o Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The previous checkpoint described chore/parity-upgrade, which has since merged. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
# Conflicts: # .beads/issues.jsonl
…t add git refuses any `git add` naming a path that matches an exclude pattern, regardless of whether the path is already tracked. bd's auto-export hook runs `git add .beads`, so it failed on every create/close, and resolving a merge conflict in issues.jsonl needed -f. Narrow the pattern to .beads/* with a negation for issues.jsonl. Directories are pruned whole, so embeddeddolt/ (88M) and backup/ (53M) stay out. Closes gopherstack-nejg
Closes gopherstack-nejg Closes gopherstack-ky42
…ings Refs gopherstack-7rq1
…count The outpost path kept a maxInstancesPerRunInstancesRequest-sized capacity hint, reserving ~16KB for a one-instance request. The non-outpost path at store.go:956 already solved this: make([]*Instance, 0) with no hint and //nolint:prealloc, keeping count out of the make() size so CodeQL alert 253 (go/uncontrolled-allocation-size) stays closed. Mirror that here. Extract the ID-minting loop into newOutpostReservedInstanceIDs. The new test asserts cap(ids) <= count*4, which fails against the old fixed-1000 code for any count under 250. Closes gopherstack-2vgi
…efix on the wire Shape-only, deliberately never populated, following b4f91c2. Gopherstack has no real dual-stack endpoint, and a fabricated dialable URL is worse than an absent field. Also correct the PARITY.md gap entry: GetHlsManifestConfiguration does not exist in mediatailor v1.63.4 (48 ops, no such operation), and there is no separate SessionInitializationEndpoint type carrying its own dual-stack prefix - that field appears once, on PlaybackConfiguration, already covered by gt9o. Closes gopherstack-ic73
…ations All six take a required ResourceId member (workspaces v1.73.1, serializers.go 8368/8423/8442/8461/8480/8499). Gopherstack read DirectoryId, so every real client's identifier was dropped and the call looked for a key no client sends. The tests asserted DirectoryId too, so they enshrined the bug instead of catching it. Not a blanket rename: ModifyEndpointEncryptionMode really does take DirectoryId, and ModifyClientProperties already read ResourceId. Both verified and left alone. Also wire ModifyCertificateBasedAuthProperties.PropertiesToDelete, which acts on the same persisted ds.Properties map the set path already writes. TestDirectoryModifyOps_RejectsLegacyDirectoryIdKey sends only the legacy key against a registered directory and expects 404, so a revert fails the suite. Closes gopherstack-7rq1
…ed 200 The real key is Identifiers.DeleteClusterSnapshotMessage.N.SnapshotIdentifier. The handler read the parent key directly and then fell back to a second form, and neither is anything a real client sends - so every batch delete succeeded loudly and deleted nothing. Three existing tests posted the fallback shape, so tests and handler agreed on a request format AWS never produces. Third instance of that pattern this campaign. Three partner ops emitted ClusterIdentifier, which their real outputs do not carry. A test asserted its presence by substring, entrenching the invention. Two custom-domain ops dropped CustomDomainCertExpiryTime entirely - no field existed for it. Generated the same fabricated-but-consistent way Redshift Serverless already handles its own cert expiry, rather than inventing a second convention. Two snapshot-schedule ops dropped Tags the backend already accepts and stores. NextInvocations left unfixed and documented: its cron grammar differs from the one this service already parses for scheduled actions, and adding a second parser is disproportionate to the gap. Empty-envelope class ABSENT in redshift - nine genuinely-void deletes confirmed void against the real SDK rather than 'fixed'. Coverage stated as found: redshift classic exhaustive at ~120 ops, serverless sampled, and the other four services sampled at 10-12 mutating ops each on top of their existing same-week field-diff passes. Refs gopherstack-7185
…client sends Query-protocol list members are wrapped in a per-type element name, not the generic member. neptune read member everywhere: SubnetIds.member.N where the real key is SubnetIds.SubnetIdentifier.N, and the same for VpcSecurityGroupIds.VpcSecurityGroupId.N and AvailabilityZones.AvailabilityZone.N. Worst is the shared filter parser. It read Filters.member.N.Name and Values.member.1 where the real serializer sends Filters.Filter.N.Name and Values.Value.1, so EVERY filter on DescribeDBClusters, DescribeDBInstances and DescribePendingMaintenanceActions was silently ignored - unfiltered results returned as though the filter had applied. Roughly sixteen tests posted the wrong keys. One asserted that subnet ids it had never successfully sent appeared in the response, which is a fabrication ratified twice over. Found response-side while fixing the third: xmlDBCluster had no AvailabilityZones field at all. THE SWEEP DIRECTION WORKED, and its negative half is worth as much. Checking tests as claims against the SDK, the agent first asked which services CAN have this bug - then proved elb, iam, sts, sns and ses structurally cannot, because every list in those five serializers uses the generic member wrapper with no custom overrides. Four services were already fixed by earlier passes. That narrowed twelve candidates to two. Closes gopherstack-rip4
…ur ops unreachable The generated-template family is the worst and was found incidentally while writing a regression test for something else. Update, Delete, Describe and Get all read GeneratedTemplateId where the real wire key is GeneratedTemplateName, so all four were unreachable by any real client - and an existing test masked it by accepting HTTP 400 as a pass. Nine cloudformation ops dropped identifiers their real outputs carry, including OperationId on CreateStack, UpdateStack and RollbackStack. UpdateStackSet and ImportStacksToStackSet were the notable ones: the backend already computed the operation id and threw it away. route53 invented two elements that are not on the wire at all. elbv2 dropped three members from its subnet and security-group modify ops. apigateway's shared RestAPI model was missing version, securityPolicy and warnings across four ops. TWO CORRECTIONS TO MY OWN DISPATCH. apigateway is REST-JSON and case-SENSITIVE, not query/XML as I told the agent - it checked rather than trusting me. And the scripted diff had a 65 percent false-positive rate here, mis-attributing anonymous struct literals to unrelated named types; every flag was hand-read and several confirmed clean rather than 'fixed'. The method scales, but only with that discipline. Coverage stated honestly: cloudformation, route53 and elbv2 exhaustive; apigateway SAMPLED - all 22 deletes clean, ~20 creates diffed, ~45 updates not reached. Named as the weakest-covered service. Six backend signatures widened to return values that were being discarded; full build verified across every caller. Also reverted fieldalignment's collateral reordering of two elbv2 test files that carried deliberate ordering with justifying nolints. Refs gopherstack-7185
…thing Three were not merely lax - the request never reached the operation at all, and the accepted failure code hid it permanently. Two organizations tests posted a nil body, so json.Unmarshal on zero bytes always errored and ListCreateAccountStatus and ListHandshakesFor* were ALWAYS returning 400. A ram test called a route that does not exist, with an ARN carrying both a typo and a nonexistent permission name, so it always got 'unknown action'. All three passed for as long as they existed. The autoscaling one is the clearest artefact: Code == StatusOK || Code != StatusInternalServerError accepts every status except literally 500, and the response body it captured was discarded into a blank identifier. Also an iam test accepting 200, 404 or 500, an ssoadmin update never checking the name changed, and - directly below the cloudformation test that motivated this class - its sibling carrying the identical unfixed pattern. All nine now assert what a caller observes: the id returned matches the one sent, the created record appears in the list, the updated name reads back. THE HONEST RESULT: no application-logic bug sat beneath any of them. Every backend op worked once driven properly. So the yield here is different from the wire sweeps - what these tests concealed was their own emptiness, plus three requests that never arrived. Ten further candidates examined and deliberately left: 200-or-201 on quicksight creates and 200-or-202 on pinpoint async ops are legitimate status variance with real content assertions following, and one honestly-named Smoke test is covered properly elsewhere. Refs gopherstack-mslf
…ds silently no-op'd TestInvokeAuthorizer shares its URL with Get, Update and Delete and is distinguished only by method. The router's authorizer route handled GET, PATCH and DELETE but not POST, so every real client call 404'd. The PATCH bet paid off, though not where I guessed. patch.go itself is mature and handles the real key set correctly - it has dedicated resolvers per resource family and real-client tests already. What it cannot catch is a patch landing on a field the target struct does not have, which silently does nothing and returns the unmodified resource. Two instances: /securityPolicy on UpdateRestApi, already named-but-unfixed in PARITY.md since 11 August, and /authType on the authorizer ops - that one missing in TWO layers, the exported input types AND hand-duplicated local decode structs in the handler. Re-swept every other Update op for that same two-layer shape and found none; the rest embed or unmarshal straight into their exported input. GetUsage and UpdateUsage emitted items where the deserializer reads values, so a real client's Items was always empty - and a test asserted the wrong key. TestInvokeAuthorizer also emitted authorization as an integer where the real type is a map of string to string list, which HARD-ERRORS a real client rather than failing quietly, plus an invented context key. Deployment.apiSummary and Stage.webAclArn added; TestInvokeMethod gained multiValueHeaders in both directions. Five findings reported and deliberately not fixed, including two invented wire keys whose removal needs a persistence-table migration that is not worth the risk for keys real clients ignore. Refs gopherstack-7185
…us five empty tests Three sqs filter-policy tests were COMPLETELY EMPTY - no invocation, no assertion - while promising coverage of the seven-operator matcher that governs SNS-to-SQS delivery. The purest form of this class: a test that cannot fail. Replaced with sixteen table cases driving real Publish through ReceiveMessage. The one real wire bug came from the bare-NotNil pattern: DescribeEngineDefaultParameters and its cluster sibling never echoed DBParameterGroupFamily, which the real EngineDefaults declares. Both tests asserted only that a response existed. Three more tests tightened with no bug beneath: a revoke that never checked the CIDR was removed, a describe that never checked the returned protection, and an update that never checked the updated fields. VOLUMES, because they bound the class rather than close it: the NotNil pattern had ~179 hits, machine-triaged to 48 where it is the last statement, ~35 read, 5 real. The behaviour-promising-name pattern had ~1878 test functions, triaged to 173 lacking content assertions, ~25 read, 1 real - and most triage flags were false positives from the detector not counting Len, Empty, True and False as content checks. Both remain far from exhausted, and the low hit rate is itself the useful signal. Reported and not fixed: two independent filter-policy engines exist, and the sqs-side one is dead for the exclusion path because SNS already prunes non-matching subscribers before it runs. Refs gopherstack-mslf
The real SDK sends DELETE on a six-segment path ending /cache/data. The router checked for five segments ending /cache, so it never matched and fell through to the unknown-operation sentinel. A pre-existing test hand-built the same five-segment path and thus masked it - the same antipattern this campaign has now found five times. The route table that guards this service grew from 41 ops to all 124, so the gap that hid FlushStageCache is closed structurally rather than by one fix. s3's ListDirectoryBuckets is NOT fixable and is now documented as such. The router keys on a list-type=directory query parameter that no real client ever sends: AWS distinguishes that op from ListBuckets purely by hostname, s3express-control versus s3, and gopherstack has one endpoint. So every real call falls through to ListBuckets and returns the wrong bucket set with a 200. Swapping one fabricated discriminator for another would only move the lie, so it carries a landmine comment and a PARITY gap entry instead. Four of the six services in scope were already covered by earlier route sweeps driving both ExtractOperation and Handler; their suites were re-run to confirm no regression rather than re-derived. The new ground was s3 and apigateway's restapis subtree, which a prior note had explicitly flagged as needing a method of their own. Two ops confirmed correct and recorded so they are not re-suspected: s3 disambiguates CopyObject and UploadPartCopy by the copy-source HEADER rather than by method or query, which reads like a bug and is not. Closes gopherstack-0bq8
…assing ecs 77, ssm 152, kms 54, stepfunctions 37, secretsmanager 23 - every op in each pinned SDK, cross-checked against GetSupportedOperations before a test was written. Both ExtractOperation and Handler are driven, matching the convention the other 25 tables follow, because the first is an observability hook and only the second is the dispatch contract. THE USEFUL RESULT IS THE BOUND, not the zero bugs. These five dispatch by X-Amz-Target, never by path - every op posts to / with the same method, and the only per-op signal is the target header. So there is no path template to get wrong, and this whole protocol family is structurally immune to the class that made apigateway's FlushStageCache unreachable. What remains possible is narrower and worth guarding: a dispatch key that does not exactly match the real op string. These tables catch that by driving the REAL SDK's target rather than gopherstack's own name for the op, and case-sensitivity makes it a live risk. A static diff of implemented keys against serializer-derived names found no mismatch in either direction, then the tests confirmed it by actually dispatching. That bound matters for scope: roughly 130 of 161 services are JSON-family, so the unreachable-op class is concentrated in the REST and query minority rather than spread across the repo. Also reconfirmed independently: stepfunctions omits DescribeStateMachineVersion because the SDK has no such op either. Refs gopherstack-n1mb
s3 112, iam 176, dynamodb 58, sns 42, sqs 23 - every op in each pinned SDK, built from httpbinding.SplitURI in the serializers rather than from the handlers' own routing, so the table cannot inherit the router's mistakes. s3 needed more than the static template. Several ops are distinguished by REQUIRED DYNAMIC members the template cannot show - UploadId and PartNumber for UploadPart, the copy-source header for CopyObject and UploadPartCopy, an annotation name, four config ids. Without reading each leaf handler's HttpBindings the synthetic requests would not match what a client really sends, and the table would have passed vacuously. Two per-service verification quirks worth recording. s3 computes ExtractOperation from a field each leaf handler tags itself with, so one read after Handler proves routing AND self-identification together - there is no separate unmatched-route sentinel. And iam REUSES its InvalidAction error for ordinary bad input, so checking that code alone produced eleven false positives; the table matches the exact dispatch-miss phrase instead. The table was proven capable of failing rather than assumed: breaking PutBucketAcl's query check made it fall through to CreateBucket and the test caught it. ListDirectoryBuckets is skipped with its reason rather than asserted, since AWS distinguishes it by hostname alone. No other structurally unreachable op found in these five. No bugs. With the 343 target-header ops tabled earlier, 754 operations across ten services now carry a standing route assertion. Refs gopherstack-n1mb
securityhub 116, xray 38, glacier 33, efs 31, each matching its pinned SDK's real op count exactly. All four drive Handler as well as ExtractOperation. Proven capable of failing rather than assumed: mistyping one securityhub path literal made that op fall through to Unknown and the table caught it. I told the agent glacier is REST-XML. It is REST-JSON 1 - the agent read the serializers rather than trusting me, and _PROTOCOLS.md already said so on a row that was hand-spot-checked. That is the third protocol claim I have gotten wrong from memory while holding a table built precisely to stop that. Two sentinel subtleties worth recording, both of the iam InvalidAction kind. xray's legitimate not-found errors CONTAIN the string 'not found' as JSON, so a substring check would have false-positived; the table compares against the bare plain-text sentinel exactly. The other three use a phrase confirmed absent from non-test code. Systematic check for the s3 vacuity trap - a shared method and path discriminated by a dynamic member the template cannot show - found exactly one collision in all 218 ops: glacier's AddTags and RemoveTags, both POST on the same path, separated only by an operation query baked into each op's own template. Already handled correctly. So no additional dynamic-member verification was needed anywhere else in this batch, which is a real bound rather than an omission. Glacier's unusual shapes held: the account-id segment including AWS's dash placeholder is opaque to the router, and its multipart tree discriminates cleanly by method on one identical path. Refs gopherstack-n1mb
…vert - 319 ops 112, 100, 73 and 34, each matching its pinned SDK's real op count. All four drive Handler as well as ExtractOperation. Zero method-and-path collisions across all 319 ops, checked systematically rather than assumed. So the s3 vacuity trap - a shared route separated only by a dynamic member the static template cannot show - does not arise here at all. With the previous batch's one collision in 218 ops, that trap now looks rare enough to be a named exception rather than a general hazard. Sentinels were verified before being trusted, which two earlier services proved necessary. sesv2 turned out to have TWO distinct dispatch-miss modes - an unmatched path and a recognised op with no dispatcher case - and both are driven. Each phrase was grepped to confirm it appears exactly once outside tests. Proven able to fail: removing one case from mediaconvert's read-only dispatch made that op fall through to the mutating table's default, and the test caught it with the exact NotFoundException body. mediaconvert's table excludes UpdateJob deliberately - it is not a real SDK op, and the handler already documented that. Three unusual-but-correct routes recorded so they are not re-suspected: a DELETE-based CancelJob, a PUT on the tags path, and a prefix ordering that puts jobsQueries before jobs. Protocols taken from _PROTOCOLS.md rather than from my memory this time. Refs gopherstack-n1mb
…ication bugs amplify 37, bedrockagent 75, elasticsearch 51, ram 35, grafana 25, mwaa 12, each matching its pinned SDK's real op count. The three bugs are all observability-only, and that distinction is the interesting part: runtime dispatch was correct in every case, so a table driving only Handler would have passed. PrepareAgent had no classification case for its shape; ValidateFlowDefinition was misclassified as PrepareFlow because both are a single segment plus POST; and an elasticsearch inbound-connection case sat in the OUTBOUND classifier, dead because the inbound prefix always routes first. All three would have mislabelled metrics and logs indefinitely. That is the inverse of the reason we drive Handler as well as ExtractOperation - one catches unreachable ops, the other catches mislabelled ones, and this batch needed the second. The sentinel work keeps paying. bedrockagent has EIGHTEEN distinct miss branches behind one exception type. amplify has two miss modes, and its not-found sentinel collides on substring with real domain errors, so the table matches the exact JSON fragment rather than a bare substring - the same trap xray and iam set. mwaa also has two. Zero method-and-path collisions across all 235 ops, so the vacuity trap now stands at one in 772. ram's internal ListTagsForResource is excluded rather than tabled: its own comment says it is not a real SDK op, verified against botocore's service definition. Proven able to fail on already-clean code - removing grafana's GET case made DescribeWorkspace classify as empty. Refs gopherstack-n1mb
…ration, plus 732 ops tabled The iot findings are the worst of the campaign. DetachThingPrincipal did not 404 - it dispatched to DeleteThing. EnableTopicRule and DisableTopicRule dispatched to CreateTopicRule. A caller detaching a principal destroyed the thing instead. Also an AttachPrincipalPolicy and DetachPolicy name mix-up mapping the wrong op to a real path, and a CA-certificate family on a path that does not exist. quicksight had four unreachable ops: two asset-bundle ops missing a literal path suffix, and two that accept only PUT where the real method is POST. bedrock's PrepareAgent was unreachable, and its in-package agents sub-API recognised only 10 of its 75 ops. Nine of those share a collection path with a PUT sibling and are distinguished by method - real AWS uses POST for the List where gopherstack conflated POST with Create. About thirty more bedrock ops dispatched correctly but classified as Unknown, which is the observability half this table catches and Handler alone does not. Tabled: bedrock 108, its agents sub-API 75, quicksight 277, iot 272. quicksight and iot are the two services flagged early in this campaign as sitting in the gap between sweeps - the gap is now closed with a standing guard. iot's existing whitebox test had already TRACKED 24 of these as known-unfixed gaps. They are now closed and that list updated. A test that records known breakage without failing is a coverage metric agreeing with itself. Proven able to fail per service, and the iot proof is the point: reverting the DetachThingPrincipal fix made it mis-route to DeleteThing rather than 404. Refs gopherstack-n1mb
… marks optional The real shape requires only the provider role ARN and URI. A client omitting Name - as the service's own test did - got a spurious 400. It survived because the test called t.Skip with the reason 'recommender creation returned 400, skipping rest of test'. So the failure was observed, described accurately, and converted into a pass, leaving the whole CRUD path unexercised. A sibling table case encoded the same wrong requirement as a passing assertion named rejects_empty_name. Both are corrected: the skip is now a require, and the table asserts Name is OPTIONAL while checking the two fields that genuinely are required. THE SWEEP'S WIDER RESULT IS THAT THIS CLASS IS RARE HERE. Four distinct list mechanisms and all ten t.Skip sites in the repo were checked, and three of the four mechanisms are legitimate ratchets rather than graveyards. The sdk_completeness pattern across ~160 files tracks entirely-unimplemented ops and is backed by a gate that fails on any stale entry; redshift's history shows dozens removed as ops landed. sesv2's three-entry gap list cites SDK lines and is guarded by a hard bucket-count assertion. And iot's list - the instance that motivated the issue - is already empty, closed by the pass that found it. So the pathology was real and is not endemic. That bound is the useful half. Refs gopherstack-2y20
batch 45, s3control 97, accessanalyzer 39, resourcegroups 23, scheduler 12, pipes 10. Every count matched its service's own GetSupportedOperations exactly, so no op was undercounted. s3control was flagged as the likeliest place for the vacuity trap - REST-XML with account-id routing - and came back with zero collisions across 97 ops. That keeps the campaign-wide count at one collision in roughly a thousand ops, which settles it as a named exception rather than a hazard to design around. The sentinel check earned its place again, on scheduler. Its real not-found errors legitimately contain the string 'not found', which collides with the routing-miss sentinel of the same text - a bare substring assertion would have failed on working code. Resolved by matching the body exactly, since misses write bare text and domain errors write JSON. Fifth service where that check prevented a phantom bug. Each table proven able to fail by mis-wiring one route and watching it dispatch to a sibling - CancelJob to TerminateJob, GetSchedule to DeleteSchedule, StartPipe to StopPipe, and three more. Two structural notes recorded rather than 'fixed': resourcegroups' handler comment claims AWS uses DELETE for Untag where the pinned SDK sends PATCH - routing is correct and only the comment is stale - and s3control's synchronous MRAP delete is unreachable by design, with the async route already tabled. Refs gopherstack-n1mb
mq 25, appmesh 38, serverlessrepo 14, mediapackage 19, emrserverless 22, networkmonitor 12. No bugs, no exclusions, no stale-comment cases. Three method conventions confirmed from the serializer rather than assumed, all of which REST intuition would get wrong: appmesh uses PUT for every Create, serverlessrepo uses PATCH for UpdateApplication, and mq carries a versioned v1 prefix while mediapackage's paths are bare. The sentinel check saved a sixth service. appmesh's legitimate not-found errors are all qualified - 'mesh not found', 'virtual router not found' - so every one contains the bare miss sentinel as a substring. Exact body matching instead, verified against all seven emission sites. One scope limit worth recording rather than glossing: mediapackage's bare paths are shared with iotanalytics, mediatailor and fis at the same prefix, and are disambiguated a layer up in RouteMatcher by SigV4 service name. Every route table in this campaign drives ExtractOperation and Handler directly, so none of them covers that layer. That is a real gap in what these guards assert, not a property of mediapackage. Each table proven able to fail by mis-wiring a route and watching it dispatch to a sibling - appmesh's swap moved five subtests at once. Refs gopherstack-n1mb
detective 29, fis 26, iotanalytics 34, managedblockchain 27, resiliencehub 63, rolesanywhere 30. Every route matched its serializer on first pass. The sentinel check caught two more real substring collisions. iotanalytics' domain errors read 'channel not found' and managedblockchain's read 'ResourceNotFoundException: resource not found' - both contain their service's bare miss sentinel, so a substring assertion would have failed on working code. Both resolved by decoding the field and comparing exactly. Eight services now where verifying the sentinel before trusting it was load-bearing. Two useful negatives from the same check: rolesanywhere cannot collide because its domain errors carry no message text at all, and fis cannot because its not-found sentinels are single CamelCase tokens. Also found dead code in fis - a second unknown-operation branch unreachable via HTTP because the path parser only ever returns a known constant or empty, and empty short-circuits earlier. The failure proofs were chosen to mirror real bugs rather than to be convenient. iotanalytics' DeleteChannel was wired to DescribeChannel and rolesanywhere's GetTrustAnchor to DeleteTrustAnchor - a destructive op shadowed by a read, and a read turned destructive. Those are the shapes that made iot's DetachThingPrincipal delete things, so proving the guard catches them is worth more than proving it catches a 404. Refs gopherstack-n1mb
dlm 8, account 16, mediastoredata 5, apigatewaymanagementapi 3, cloudfront keyvaluestore 6. All clean on first pass. I suspected cloudfrontkeyvaluestore had s3's ListDirectoryBuckets problem - an op distinguishable only by hostname and therefore unreachable in a single-endpoint emulator. It does not. The agent read the endpoint ruleset rather than accepting the premise: AWS derives a per-ACCOUNT virtual host from the KVS ARN, not per-store, and the full path carrying that ARN as a URI label is generated independently of the host and sent unchanged either way. So every op stays distinguishable by path. Corrected finding, not the assumed one. apigatewaymanagementapi's live-handle oddity turned out to be a persistence concern with no bearing on routing; its three ops share one path and separate by method alone. Its gopherstack-only diagnostic endpoints are excluded rather than tabled. A new kind of clean bound from the sentinel check, in two services: the dispatch-miss branch is structurally unreachable by any legitimate request. mediastoredata's fires only for methods outside the four the API uses, and apigatewaymanagementapi's only for paths lacking a prefix RouteMatcher already requires. Previous bounds were about sentinels that could not collide; these cannot fire at all. Both failure proofs mirror the destructive shape deliberately - GetLifecyclePolicy wired to Delete, GetKey wired to DeleteKey. Refs gopherstack-n1mb
…lus 43 ops tabled modelPathOperation matched on suffix alone, so InvokeGuardrailChecks - whose real path is POST /guardrail-checks/invoke - classified as InvokeModel because both end in /invoke. Dispatch was always correct, since Handler prefix-matches rather than suffix-matches, so this was purely observability. Fourth classification-only bug this campaign, and all four were invisible to a table driving Handler alone. iotdataplane is a ninth sentinel-collision service, and the sharpest yet: its miss text 'not found' is a substring of three domain errors that reach the wire verbatim - shadow, retained message and connection not found. A substring assertion would have failed on legitimate 404s raised by the table's OWN test cases. Ops tabled: iotdataplane 11, bedrockruntime 11, polly 10, rdsdata 6, sagemakerruntime 3, appconfigdata 2. iotdataplane's supported-operations list claims 14 because three are gopherstack-only admin extensions with no AWS wire op; excluded rather than tabled, as already documented in code. A clean negative against my own expectation: I warned these data-plane services would need header or content-type disambiguation because they stream audio and model responses. None did. Method plus static path was sufficient for all six, and rdsdata has no path parameters at all. Failure proof chosen to hit real dispatch rather than labelling - swapping iotdataplane's GET and DELETE classification would have made a real GetConnection call delete the connection. Refs gopherstack-n1mb
…s - 1244 ops ec2 785, rds 164, redshift classic 145, cloudformation 90, redshift serverless 60. ec2's real op count came in at 785 against my ~500 estimate; the agent tabled it in full rather than partially, since extraction and generation were mechanical. The static two-way diff before any test ran is what earned its place. It found a DEAD dispatch key in rds - GetPerformanceInsightsMetrics matches no real RDS Action at all - and five redshift-serverless ops with no dispatch entry, the Reservations family the SDK gained and this backend never implemented. Both excluded rather than tabled, so the tables assert what exists. Neither would have surfaced from testing alone: a dead key is never exercised, and an unimplemented op has nothing to drive. Sentinels verified against the iam pattern and all five are clean - none of these services reuses its dispatch-miss error for ordinary bad input, unlike iam's InvalidAction. Recording that as a bound rather than a non-event. Failure proof chosen for shape: mis-keying DeleteDBInstance to DeleteDBInstances makes a destructive op unreachable, and the table caught it. Refs gopherstack-n1mb
…cloudwatchlogs - 949 ops sagemaker 403, glue 299, cognitoidp 129, cloudwatchlogs 118. glue turned out to be 299 rather than the ~200 I estimated - real count, not the guess. The agent went past the brief in the way that mattered: it diffed the ACTUAL dispatch map rather than only the reported GetSupportedOperations list. That found cognitoidp wiring AdminSetUserMFASetting, which is not a real SDK op name - the real one is AdminSetUserMFAPreference, separately and correctly wired. Dead cruft, unreachable by any client, and invisible to a diff of the reported list because that list already omits it. Recorded, not 'fixed'. It also declined to inherit the sentinel convention. Three of the four use UnknownOperationException; sagemaker does not - its text is 'unknown action', and the assumed literal appears nowhere in its non-test code. Each was grepped to a single production call site. And it distinguished a real risk from a false one: sagemaker dispatches by switch rather than map, so phantom keys hide differently. Grepping every case label turned up one hit that was a field-decoding switch, correctly dismissed. Failure proof: renaming glue's DeleteTable binding to GetTable made the destructive op unreachable while GetTable kept passing - now silently bound to the delete handler. Exactly the shape that made DetachThingPrincipal delete things. Refs gopherstack-n1mb
…lus 323 ops tabled DeleteCacheCluster and DeleteReplicationGroup indexed Data[0] straight after a Describe that had succeeded with an empty slice. Query semantics mean an empty id describes ALL, so on a fresh backend both panicked rather than returning NotFound. Found by driving the table live, not by reading - each function already had the correct fault on a sibling path. eventbridge needed the most judgement and got it. Its supported-operations list reports 79 where the service has 57: twenty-two belong to the separate Pipes and Schemas services, both REST-JSON in their own SDKs, hosted in this directory behind a fabricated target convention no real client can send. All excluded. Four more keys are dispatchable but already documented in-source as dead. The agent also used the REAL AWSEvents target prefix rather than the existing tests' AmazonEventBridge one, which only passes because ExtractOperation never checks the prefix - so those tests would accept a target AWS does not send. memorydb carries one excess key, ExportSnapshot, verified against botocore as not a real op and already documented. Excluded rather than fixed. autoscaling and directoryservice diffed exact in both directions with nothing dead or missing. Failure proofs on destructive ops in two services - mis-keying DeleteAutoScalingGroup and DeleteDirectory. Refs gopherstack-n1mb
… - 423 ops dms 119, awsconfig 102, workmail 92, transfer 71, kinesis 39. All five diffed clean in both directions - no dead key, no gap - unlike rds and redshift-serverless in earlier passes. Two services would have produced false positives from an inherited sentinel. workmail's dispatch-miss maps to InvalidParameterException, THE SAME WIRE TYPE its ordinary validation errors use, and transfer's maps to InvalidRequestException, likewise shared. Asserting on the wire type would have been the iam trap exactly. Both assert on message text instead, each grepped to a single production call site. awsconfig's miss is not wire-typed at all. The dms diff nearly produced a false GAP for the opposite reason: four ops are dispatched by literal string keys where every other entry uses an opXxx constant, so an identifier-only grep missed them and reported four ops unimplemented. Re-extracting for both key styles resolved it to 119 of 119. That is the same shape of risk that hid cognitoidp's phantom key, in reverse - and kinesis has the same exposure, its supported-operations list being hand-maintained separately from its real map. kinesis was flagged for disguised stubs, so all 38 dispatched ops were checked for hollow handlers. None found. SubscribeToShard is covered separately because it bypasses JSON dispatch for the binary event-stream protocol. Failure proof on a destructive op, and the report notes the limit honestly: the mis-wired sibling kept passing, since this table proves dispatch RESOLVES, not that it resolves correctly. Refs gopherstack-n1mb
workspaces 91, ssoadmin 79, waf 77, organizations 63, datasync 53, elbv2 51. Every one diffed to exact real-op parity in both directions - nothing dead, nothing missing, nothing excluded. The extraction trap fired again and was caught. organizations initially showed a false gap of one, because dispatchRoot tests ListRoots with a bare if where every sibling helper uses a switch. Same shape as dms's four literal-keyed ops last pass. Two services, two passes, two different idioms - so extracting for one style and trusting the count is now demonstrably unsafe. Target prefixes confirmed unguessable again: ssoadmin's is SWBExternalService, datasync's is FmrsService, waf's is AWSWAF_20150824. None derivable from the service name. Sentinel handling split cleanly. Four services wire-code their dispatch miss uniquely and can be asserted on type; datasync and workspaces share their miss type with real validation and internal errors, so those assert on message text. That is now eleven services where checking rather than inheriting mattered. elbv2 had no prior table - its existing audit test covers draining, DNS format and pagination, not dispatch - so this is additive rather than duplicate. Failure proofs on a destructive op in each of the six. For elbv2 the agent also reproduced the documented LIMIT: shadowing DeleteLoadBalancer with DeleteTargetGroup's handler still passes, because the table proves dispatch resolves, not that it resolves correctly. Refs gopherstack-n1mb
personalize 71, athena 70, emr 65, codebuild 59, ecr 58, swf 39. All diffed exact in both directions. The sentinel check was load-bearing in four of six, and athena is the clearest case yet: its dispatch-miss shares a wire type with FOUR other errors - not-found, already-exists, protected and validation are all literally the same constructed error. Asserting on type there would have passed against a handler that had stopped dispatching entirely. codebuild and personalize share the same shape; swf returns its miss with no type field at all. swf's prefix is SimpleWorkflowService with no version suffix, unlike every other older service tabled so far - read rather than assumed, as instructed. A real finding recorded rather than fixed: personalize dispatches its two Runtime ops through the control-plane target-header mechanism under a FABRICATED AmazonPersonalizeRuntime prefix. The real personalizeruntime SDK is REST-JSON and sends no target header at all - it POSTs to /recommendations directly. So a real client's request cannot reach that handler. Stronger than the eventbridge case, where the fabricated prefix was merely unvalidated rather than contradicted by the protocol. The package's own tests drive the same fabricated header, so they pass without touching the real wire protocol. emr's ListTagsForResource dispatch key excluded - no such real EMR op, already documented as scaffolding. Failure proofs on a destructive op in each of the six. Refs gopherstack-n1mb
rekognition 75, ses 71, wafv2 59, elasticbeanstalk 47, firehose 12, sts 11. Both diffs exact in both directions, no dead keys, nothing excluded. THE FAILURE PROOF CAUGHT A BUG IN THE PROOF ITSELF. rekognition's first assertion used %q formatting, which produces unescaped quotes that never appear in a JSON body where quotes are backslash-escaped. So the corrupted-key test PASSED when it should have failed - a table that could not fail, which is the exact pathology this campaign has spent days finding in other people's tests. Caught only because running the proof is required rather than trusting the assertion. Fixed and re-verified fail, revert, pass. The extraction trap appeared in a THIRD idiom. ses dispatches through an eight-deep chain of switches, each falling through its own default into the next helper. Stopping at the first default would have undercounted; extracting every case in every link landed exactly on 71. After dms's literal string keys and organizations' bare if, that is three distinct idioms in three passes. rekognition's sentinel is the catch-all default of handleError rather than a dispatch-specific type, so asserting on type would have been structurally unsafe even though nothing leaks into it today. Message text instead, following athena. Two useful structural notes. elasticbeanstalk's dispatch-miss and its two sibling errors all wrap the SAME underlying error, and separation depends on errors.Is matching each package var's own pointer identity - verified rather than assumed. And rekognition's supported-operations list is built by ranging over the dispatch map, so it cannot diverge from it, collapsing what is normally two independent diffs into one. Refs gopherstack-n1mb
codecommit 79, codedeploy 47, codepipeline 44, verifiedpermissions 34, kinesisanalyticsv2 33, textract 25. Three lists extracted per service - real SDK targets, the reported op list, and the actual dispatch map - and all three matched byte for byte in every direction. All six build their reported list as a hand-maintained literal rather than by ranging over the dispatch map, so unlike rekognition the two diffs here are genuinely independent checks. Worth stating explicitly, since a collapsed pair looks identical in a report. The codedeploy failure proof did double duty. Mis-wiring DeleteApplication confirmed the table catches it AND confirmed that asserting on wire type alone would NOT have, because the mis-wired response still carried InvalidRequestException. That is the sentinel trap demonstrated rather than argued. Sentinels split three ways: two services wire-code their miss uniquely, three share it with ordinary validation errors, and kinesisanalyticsv2 has two separate miss paths emitting the same type outside the shared error handler. codecommit is the sharpest - its miss has no table entry at all and falls through to the error handler's loop default. Two prefix oddities: textract's is bare Textract with no version suffix, and kinesisanalyticsv2 reuses v1's KinesisAnalytics_20180523 rather than carrying its own. verifiedpermissions is the only JSON-RPC 1.0 of the six. No extraction trap in this batch - all six use a single flat map, none of the three idioms found in earlier passes. Refs gopherstack-n1mb
lightsail 161, route53resolver 72, neptune 70, docdb 55, shield 36, elb 29. Six services, five different dispatch idioms: neptune chains seven switches, docdb six, shield tries four helpers returning ok-flags, elb and lightsail use flat maps. The extraction trap is not an occasional hazard - it is the norm, and the only safe method is re-extracting per service rather than reusing the previous pass's script. route53resolver builds its reported op list by ranging over the same map Handler uses, so the two diffs collapse into one self-referential check. The agent re-derived 72 independently from all thirteen builder functions rather than trusting it. lightsail is the opposite - a hand-written 161-entry literal genuinely independent of its sixteen-function merge, so two real diffs. Three of six could not safely assert on the wire type. shield's dispatch-miss shares InvalidParameterException with two other errors, and the code says so in its own comment; lightsail's shares InvalidInputException with validation errors; route53resolver's branch emits NO type field at all. Message text in all three, and the failure proofs then confirmed each prediction empirically by printing the actual body. shield's __SimulateAttack is a gopherstack-internal test hook with no real target - excluded rather than tabled. route53resolver's prefix carries no version suffix, like textract and swf. That is now three of the last eighteen, so the version-stamped form is a convention rather than a rule. Refs gopherstack-n1mb
Eleven commits off the follow-up queue. Every issue was spot-checked against live code before an agent was spent on it, which turned out to matter — two of the queued issues were already fixed.
Fixes
apigateway snapshot version — data loss (
cb188a8a7).apigatewaySnapshotVersionwent 1→2 in d39bf33 alongside a purely additiveTags *tags.Tags json:"tags,omitempty"on the nestedstageSnapshot. An older snapshot still decodes fine withTagszero-valued, so the bump bought nothing — butRestorediscards on any version mismatch, resetting the registry and all nine dirty tables. Every instance with a persisted apigateway snapshot would have lost its state on the first start after that commit.TestSnapshotVersionGuarddid not catch it: version comparison lived only inside branches keyed on the field list changing, so version-only drift fell through silently — and the drift was real, source at 2 while the golden still said 1. Split into a purediffSnapshotswith adefault:branch, so this now fails loudly instead of riding along on the next-update.Two apigateway fixtures pinned
"version":2literally. With the constant at 2 they passed — through the discard path, not the restore path. They now pin 1 and exercise the real one.ec2 RunInstances silent clamp (
e44858734). The backend clamped count to 1000 and carried on, so cloudformation and tests calling it directly got fewer instances than requested and were told it succeeded. Now errors. The bound was also reported asInvalidParameterValue, framing gopherstack's own allocation-safety cap (CodeQL alert #253) as a malformed request; AWS documentsResourceCountExceededfor exactly this — "more instances than AWS allows in a single request... separate from your individual resource limit". EC2 models no typed exceptions in the SDK, so the code is verified against the API error-code reference and cited inerrors.go.datasync ServerHostname, all three location types (
609864859,4983d442e). NFS, then SMB and ObjectStorage.ServerHostnamewasn't declared at all, so a hostname change reported success whileLocationUrikept pointing at the old server. Each URI is rebuilt in the shape its own Create produces — these differ (nfs://host/subdir,smb://host/subdir,object-storage://host/bucket/subdir), and bucket is preserved from stored state sinceUpdateLocationObjectStorageInputhas noBucketNamemember. AWS shipped the capability on all three at once (SDK CHANGELOG:268). The SMB and ObjectStorage PARITY rows had claimedwire: fixed ... FIXED this sweepwhile the member was missing.databrew CreateJob (
f735a8a3e) and workspaces image ops (973aa011e,b4682808b). Both accepted references to resources that were never created. Validation runs before any write, so a rejected call leaves nothing behind — the workspaces tests prove that directly by asserting the ID counter advances by exactly one across a rejected create, rather than arguing it from code order.CreateWorkspaceImagewas worse than unvalidated: it tookworkspaceIdas_ /*workspaceId*/and discarded it, though the handler had been threading it through all along.CopyWorkspaceImageis the one deliberately left partly open: this service runs one backend per (account, region),b.imagesis flat andstoredImagehas no region field, so a genuine cross-region copy's source lives somewhere this instance cannot see. It validates only whenSourceRegionis empty or matches; rejecting cross-region would be more restrictive than AWS. A test pins that as a choice.Existing tests across the two services created resources against IDs that were never created — asserting behaviour the real services reject. They now create the referenced resource first rather than having the fix weakened around them.
Tooling
make lint-changed(c3d844000). Every per-change gate here has been scoped to a fixed directory, so nothing coveredtest/— which is how agovetshadow intest/integration/datasync_test.goreached a commit and was only caught by CI's repo-wide run at merge time. The new gate resolves the actual diff to package directories: working tree unioned with branch-vs-merge-base, since verifying before committing and verifying at commit time need different halves. Verified by reintroducing that exact shadow — caught, exit 1.gendocs silently dropped PARITY entries (
29d3136fc).entryLineRerequired a bare identifier for the key, so every family key naming several operations or carrying a parenthetical —AddPermission/RemovePermission,Database/TableMetadata (Get/List)— was skipped without a word. The operations badge moves 6111 → 6163 and 49 generated files change; none of it is new work, it is documentation that was written and not being read. Widening was checked against every<prefix>: {inservices/*/PARITY.md: 165 additional distinct keys match, all legitimate, nothing spurious.The silence was the real defect. A looser detector now reports entry-like lines that fail to parse, with file and line. Sixteen exist today (commas,
*,->) and were previously invisible; filed asgopherstack-42va. Warnings are non-fatal on purpose —ParseParityFilepromises graceful degradation, and CI's docs job already fails on generated diff.Docs
guardduty PARITY.md (
3ab51d46a). Each status claim was re-verified against current code before being recorded, not copied from the commit message.GetRemainingFreeTrialDaysstays gradedpartial, notok— it computes a real value under the right shape, butfeatures[]can only report the three always-on base sources. Three implemented operations had no ops-table row at all; that's the +3 in the operations badge (6108→6111), not new work.ListCoverage's filter is recorded as a gap and deliberately not built — nothing holds coverage-resource state, so it would filter a permanently-empty list and read as working.apigatewayv2 basepath transforms (
572c89ee9). Test-only.prependhad no assertion on the resulting route keys, which is how a review misread it as accepted-then-ignored. Now covers all four modes against a spec with a/v1base path and one with none, for both operations, asserting route keys rather than status codes.Gates
go build ./...go vet ./...golangci-lint run ./...go test ./...make check-pinsmake docs+ regentest/terraformThe terraform suite times out locally as one process (25m, zero
--- FAILlines — it panics on the timer with cases still mid-flight). CI shards it 8×15m, so a single local run is roughly 8× a CI chunk. CI settled it:terraform-tests, all fourintegration-testsshards, all fourunit-testsshards,lint,e2e-tests,modernize,govulncheckandcodeql (go)all passed. The local timeout was machine capacity, not a regression.Queue triage
gopherstack-66dr(route53resolverFilters) closed with no code change — already fully implemented in the same PR the follow-up was filed against.gopherstack-jni0narrowed rather than closed. My first pass on this was wrong: I greppedvalidateBasepath, saw only validation, and reported thatbasepathwas accepted then ignored. It is not —prependis implemented inapplyOpenAPIToAPI(handler_apis.go:322-324) and applied by both ImportApi and ReimportApi. Onlysplitfalls back toignore, and that was already documented honestly. It stays unimplemented deliberately: the SDK models the enum values but defers the semantics to prose, so building it would mean guessing at client-observable routing. The route-key transforms for all four modes are now pinned by tests soprependcan't regress silently.Filed
gopherstack-2vgi(ec2 outpost fixed reservation — no local CodeQL to prove a tighter shape),gopherstack-42va(16 PARITY keys with commas/*/->that still don't parse, now at least warned about).Both
gopherstack-7xcwandgopherstack-plmbwere filed and then fixed in this same PR.Two commit trailers name issue IDs that do not exist —
4983d442esaysCloses gopherstack-2xhy. I misreadbd createoutput and invented the ID; the real issue isgopherstack-7xcw, closed correctly. Recording it here rather than rewriting pushed history.Needs a human decision
gopherstack-ylyb— during PR #2414 a subagent dismissed CodeQL alert 254 viagh api PATCHwithout being asked. The SRP reasoning holds:xis a transient protocol intermediate, only the verifier persists, and a slow KDF would structurally break every real-SDK login. Butv = g^x mod Nis stored at rest, so a store leak plus known salt/pool/username permits an offline dictionary attack — the KDF-hardness CodeQL asks for is precisely what SRP lacks. That makes the honest label "true positive, unfixable without breaking the emulated protocol" rather than "false positive". No alert state was touched during this review.🤖 Generated with Claude Code