> ## Documentation Index
> Fetch the complete documentation index at: https://docs.tensor9.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Validating Your Choice

> Evaluate candidate adapters through explicit contracts, bounded checks and a production qualification record.

Check each candidate adapter at two scales: a small, understandable example and your application's real workload. Use the same acceptance criteria when comparing the results. The service profile defines the adapter contract. Your tests establish that each deployment and application use that contract correctly.

For a first experiment, use the S3-to-Google-Cloud-Storage steps below. For database atomicity or queue delivery, use the worked checks in [DynamoDB](/cloud-adapter/trade-offs/aws-dynamodb) and [SQS](/cloud-adapter/trade-offs/aws-sqs).

## General trade-offs

Compare adapters within the same permitted target environment. Record that environment before choosing the candidate backends: an Azure result does not qualify a Google Cloud deployment, even when the two mappings expose the same origin API. Each service's trade-off article lists its backends under environment headings and explains their workload fit.

### Separate the contract from qualification

| Question                                                        | Evidence to use                                                                        | Responsibility                                                    |
| --------------------------------------------------------------- | -------------------------------------------------------------------------------------- | ----------------------------------------------------------------- |
| What does the mapping preserve, change or reject?               | Directed service profile and operation details                                         | Tensor9 defines the adapter's documented behavior.                |
| Which path does this request select?                            | Profile inspection, request preview or executed explanation, depending on the question | Inspect the supplied evidence in its stated scope.                |
| Did the requested effect occur?                                 | Origin response, native state and an application assertion                             | Verify the actual resource and result.                            |
| Will this deployment meet our workload and recovery objectives? | Representative traffic, failure and restore checks                                     | The deployment and application owners qualify their requirements. |

Customers do not need to rediscover the adapter's contract by trial and error. Start from the profile and use an unexpected result as a focused debugging case. Workload qualification adds facts that a general profile cannot know, such as your key distribution, network placement and latency budget.

### Qualify the workload separately

Write an acceptance sheet for the actual application before testing. Choose numbers from its requirements and measured baseline, not from a generic example. Use the same sheet for each candidate in the selected environment.

| Area        | Record before testing                                                 | Observe during qualification                                            |
| ----------- | --------------------------------------------------------------------- | ----------------------------------------------------------------------- |
| Correctness | Required operations, values, index/query behavior and failure effects | Origin responses, target state and application assertions               |
| Traffic     | Request mix, payload distribution, hot keys and quiet periods         | Completed operations, retries and amplification                         |
| Latency     | Application p50/p95/p99 budgets and permitted error rate              | The complete application-to-adapter-to-target path                      |
| Capacity    | Physical owner, shared tenants, connection and storage budgets        | Saturation, backlog growth and recovery after a burst                   |
| Recovery    | Permitted data loss, downtime and replay                              | Usable application state after restore, including coordination metadata |
| Operations  | Alert recipient, restore authority, credentials and access            | Whether the named team can perform the actual procedure                 |

After a small check succeeds, add failure cases relevant to the chosen contract: an adapter restart, a lease expiry, an ambiguous commit, a backend failover or an isolated restore. There is no requirement to perform every possible fault on every service. Choose the cases that could violate your application's requirements.

Record the adapter version, exact backend, region, redacted configuration and workload with each result. A latency result from a local endpoint is not automatically a result for a deployed network path. A restore test without adapter-maintained metadata may omit part of the application state.

## Google Cloud

### S3 to Cloud Storage: first object check

This check writes a small object through the S3 API, reads it through both APIs and removes it. It verifies one object path; it does not establish version-history, retention, notification or workload-performance behavior.

You need AWS CLI v2, Python with Boto3, `gcloud`, an origin-side test credential profile authorized by the adapter, and a Google identity configured for the runtime. Prepare a disposable bucket mapping using [Configuration Examples](/cloud-adapter/configuration/examples#s3-to-google-cloud-storage). The native bucket and origin-facing bucket name may differ. The adapter's identity and your native verification identity are separate.

<Warning>
  The adapter runs locally, but the target resources are real Google Cloud resources. Use a dedicated test bucket and budget. Stopping the process does not remove objects or stop all target-cloud charges.
</Warning>

<Steps>
  <Step title="Install the CLI and inspect the pair">
    Install the CLI if needed:

    ```bash theme={null}
    brew tap tensor9ine/tensor9
    brew install tensor9
    tensor9 --version
    ```

    Inspect the directed profile without creating target resources:

    ```bash theme={null}
    tensor9 explain \
      -origin aws::1.0.0::s3 \
      -target google::1.0.0::gcs \
      -operation PutObject,GetObject,DeleteObject \
      -fmt Human
    ```

    Read the relevant [S3 operations and behavior](/cloud-adapter/service-catalog/aws/databases-storage/s3#on-google-cloud). Profile inspection describes the mapping; it does not authenticate the runtime or prove that a write occurred.
  </Step>

  <Step title="Start one local adapter">
    Configure the Google runtime identity and target coordinates from the configuration example, then leave this command running in its own terminal:

    ```bash theme={null}
    tensor9 adapt svc run \
      --origin aws::1.0.0::s3 \
      --backend google::1.0.0::gcs
    ```

    Copy the listening endpoint into a second terminal. Keep this test local unless you deliberately configure remote access and endpoint authentication.
  </Step>

  <Step title="Choose process-wide or client-specific routing">
    Set the printed endpoint and your dedicated origin credential profile:

    ```bash theme={null}
    export AWS_PROFILE="adapter-test"
    export AWS_REGION="us-east-1"
    export AWS_REQUEST_CHECKSUM_CALCULATION="WHEN_REQUIRED"
    export AWS_ENDPOINT_URL_S3="<endpoint printed by tensor9>"
    ```

    `AWS_ENDPOINT_URL_S3` routes S3 clients that support the standard setting in this process and child processes. It does not reroute unrelated AWS services. See the [AWS service-specific endpoint reference](https://docs.aws.amazon.com/sdkref/latest/guide/feature-ss-endpoints.html) for SDK support and precedence.

    Alternatively, pass the endpoint to one client, as the next script does. This makes the destination explicit even if process-wide endpoint configuration is absent. Both methods still use normal request signing; target-cloud credentials belong to the adapter, not the S3 client.
  </Step>

  <Step title="Write and read one disposable object">
    This example uses the origin bucket `tradeoffs-media`, mapped to the Google Cloud Storage bucket `tradeoffs-media-gcs`, and the object key `tradeoffs/check.txt`. Substitute your dedicated test bucket names throughout; native bucket names must be globally unique. Confirm that the object key is unused so the test cannot overwrite existing data.

    Save this script as `check-object.py`, replace the endpoint with the value printed by Tensor9, then run `python3 check-object.py`:

    ```python theme={null}
    import os
    import boto3

    client = boto3.client(
        "s3",
        endpoint_url="<endpoint printed by tensor9>",
        region_name=os.environ["AWS_REGION"],
    )
    bucket = "tradeoffs-media"
    key = "tradeoffs/check.txt"
    expected = b"backend-choice-check\n"
    written = client.put_object(
        Bucket=bucket,
        Key=key,
        Body=expected,
        ContentType="text/plain",
        Metadata={"purpose": "backend-choice-check"},
    )
    result = client.get_object(Bucket=bucket, Key=key)
    try:
        assert result["Body"].read() == expected, "Unexpected object bytes"
    finally:
        result["Body"].close()
    assert result["Metadata"]["purpose"] == "backend-choice-check"
    assert result["ContentType"] == "text/plain"
    print("Object bytes, content type and metadata match")
    print("Origin ETag:", written.get("ETag"))
    print("Test key:", key)
    ```

    The assertions state the expected observation; they are not a captured test result. For details of client-specific routing, see Boto3's [`endpoint_url` parameter](https://docs.aws.amazon.com/boto3/latest/reference/core/session.html).
  </Step>

  <Step title="Verify the target independently">
    Read the native object using your verification identity:

    ```bash theme={null}
    gcloud storage cat gs://tradeoffs-media-gcs/tradeoffs/check.txt
    gcloud storage objects describe gs://tradeoffs-media-gcs/tradeoffs/check.txt
    ```

    Expect the body `backend-choice-check` followed by a newline, in the configured project and bucket. Compare the full native resource identity with the mapping; the object name alone does not identify its project and bucket. Do not require the provider's native ETag to equal the S3-facing ETag; compare the property whose fidelity the application actually requires.
  </Step>

  <Step title="Remove the test object and stop the process">
    For a disposable, non-versioned bucket without retention or legal hold:

    ```bash theme={null}
    aws s3api delete-object --bucket tradeoffs-media --key tradeoffs/check.txt
    aws s3api head-object --bucket tradeoffs-media --key tradeoffs/check.txt
    ```

    Expect the final operation to report not found. Confirm the native current object is absent too. If the bucket uses versioning, deletion may leave prior versions or a delete marker; follow its ownership and cleanup policy instead of treating this as permanent removal of every version.

    Press **Control-C** in the adapter terminal after cleanup. Remove only test resources you created. Preserve redacted evidence first if an assertion or cleanup step fails.
  </Step>
</Steps>

### If the object check fails

| Observation                                       | Next action                                                                                                                      |
| ------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------- |
| Client cannot reach the endpoint                  | Check the printed endpoint, local process and network path before changing backend settings.                                     |
| Origin request is denied                          | Check the origin identity and operation authorization; a working native Google credential does not establish origin access.      |
| Native operation is denied                        | Check the adapter's target identity, resource and permissions separately from the verification identity.                         |
| Successful response, unexpected bytes or metadata | Preserve the exact request and both views, then investigate the mapped operation. More capacity is not a fix for incorrect data. |
| Timeout or missing write response                 | Inspect the target before retrying. A missing response does not prove that the write did not happen.                             |

Use [Debugging Your Adapters](/cloud-adapter/debugging/overview) and [Explaining SDK Requests](/cloud-adapter/debugging/explain-sdk). `x-t9-explain: true` executes the request and records an explanation; it is not a dry run. Add request controls before signing, and treat reports as potentially sensitive diagnostic data. A report receipt identifies evidence to retrieve, not proof that all asynchronous work completed.

## Microsoft Azure

### DynamoDB to provisioned Cosmos DB

Use the [Azure DynamoDB comparison](/cloud-adapter/trade-offs/aws-dynamodb#microsoft-azure) and [provisioned Cosmos DB configuration example](/cloud-adapter/configuration/examples#dynamodb-to-provisioned-azure-cosmos-db) to prepare a disposable table. Record the capacity owner, provisioned request units, partition design and indexes before applying traffic. Verify your application's conditional writes and reads first, then measure its key distribution and request-unit demand. A successful point write does not establish multi-item atomicity or adequate capacity for a hot partition.

### SQS to Service Bus or PostgreSQL

Compare the candidates in [SQS on Microsoft Azure](/cloud-adapter/trade-offs/aws-sqs#microsoft-azure). Apply the same send, receive, acknowledgement and redelivery assertions to each. Inspect delivery state using that backend's native tooling; a Service Bus observation is not evidence about a PostgreSQL queue. For the complete database-and-queue workflow, use the [Azure order-processing example](/cloud-adapter/trade-offs/worked-examples#microsoft-azure).

## Private Kubernetes

### PostgreSQL-backed data and queues

Use the [private Kubernetes example](/cloud-adapter/trade-offs/worked-examples#private-kubernetes) to compare separate database instances with shared physical capacity. Record operator, storage and backup ownership as well as application correctness. Test queue pressure alongside database traffic and restore both application data and delivery state before accepting the deployment. A ready database pod is not the recovery completion criterion; the application must resume work without losing committed results or repeating external effects.

## Next steps

### Finish with a release decision

The decision record should name the backend, accepted differences, operating owners, evidence reviewed, workload checks performed and conditions that require reconsideration. If a requirement is unmet, identify whether the cause is configuration, an application assumption, a defect or a different mapping contract before switching backends.

Keep a migration and rollback plan with that record. Changing the endpoint does not transfer data, drain messages or reverse writes already accepted by the new target.
