Skip to content

Add an Amazon Seller

Purpose and safety boundary

Use this runbook for the Amazon-v1 automatic connection lifecycle. A provider credential check is not the Connected milestone. Connected is projected only after the database readiness evaluator accepts current evidence for every required stage.

This runbook never authorizes a migration, reconciliation apply, workflow dispatch, secret change, deploy, or accounting write. The release owner must hold separate authority for each production-changing command shown below. Never paste credentials into a terminal, ticket, email, chat, or runbook.

Amazon readiness does not require QuickBooks, Ads, daily inventory, or an external sheet. Those capabilities may report a delay without blocking Amazon.

Owners

Boundary Action owner Expected evidence
Authoritative legal entity and brand Tenant owner / onboarding operator Named source recorded with the identity
Secure Amazon credential entry Authorized account operator UI reports Setting up; no credential appears in response or logs
Lifecycle execution and retry Lifecycle worker Fenced stage receipts and derived readiness
Identity conflict or credentials needed Tenant owner / onboarding operator Corrected authoritative identity or a new secure connection submission
Worker, schema, or publication incident Platform operations Sanitized reason code and restored green acceptance
Production migration, reconciliation apply, dispatch, or deploy Accountable release owner Separate change receipt and readback

1. Collect identity before credentials

Record four different identities. Never copy a label from one column into another merely because it looks plausible.

  • Workspace/organization: the tenant access boundary.
  • Legal entity: the authoritative company name.
  • Brand: the commercial brand.
  • Amazon account: the managed provider account, marketplace, and runtime seller key.

The normal Settings company-creation flow calls the transactional create_amazon_company_awaiting_credentials RPC. Its postcondition is one workspace-scoped company projection with:

  • provider_status=awaiting_credentials;
  • an inactive runtime seller and recurring_enabled=false;
  • distinct legal_entity_id, brand_id, and managed_asset_id; and
  • no inferred marketplace or merchant identity.

If the legal entity is unknown, stop at Action needed. Do not infer it from a brand, app, seller, Amazon-account, or QBO label.

Known scenario rules:

  • PartyPrints is the brand; Hemani Noon LLC is the legal entity.
  • Culinary Couture remains identity-blocked until an authoritative legal entity is supplied.
  • Keto Vitals remains awaiting credentials and recurring-ineligible.

2. Submit Amazon credentials through the secure connection surface

An authorized operator opens the company in Settings > Companies > Amazon and submits credentials through that form or an approved one-use intake link. Do not use the legacy add_seller.py credential flags or copy per-seller secrets to an operator machine.

On a successful submission, one database transaction must:

  1. record the current opaque credential version and provider verification;
  2. record the sanitized provider receipt;
  3. create or deduplicate the lifecycle run;
  4. enqueue one outbox event.

The expected response is connectionStatus=verified and lifecycle.status=setting_up, with one lifecycle run ID. A duplicate callback must return that same current run. It must not create another run or report Connected early.

3. Inspect progress without executing work

Use one explicit UUID. --plan is read-only and never claims a stage:

python3 scripts/connection_lifecycle/runner.py \
  --manifest-id <manifest-uuid> \
  --plan

Expected receipt:

{
  "manifestId": "<manifest-uuid>",
  "state": "queued|running|blocked|ready",
  "compiledRegistryVersion": "<64-lowercase-hex>",
  "stages": [{"stageKey": "identity", "required": true}]
}

The compiled and stored registry fingerprints must match. Settings should show Setting up, N/M while work is queued or running, one sanitized primary blocker when blocked, and Connected only when derived readiness is true. Optional failures remain visible as sync delays.

The durable stage receipt must contain the current input fingerprint, coverage, opaque source references, counts, and a sanitized reason code. queried_zero is valid coverage; no receipt or NOT_ATTEMPTED is not.

4. Worker execution and recovery

The normal worker polls at most one run from public.amazon_lifecycle_recovery_queue:

python3 scripts/connection_lifecycle/runner.py --poll-once

This is a production-writing command. Only the lifecycle worker or an explicitly authorized release/incident owner may run or dispatch it. Do not run it as a readiness check.

Each stage claim has a lease and monotonically increasing fencing token. A replacement claim after an expired lease invalidates the old worker's ability to publish evidence or a runtime feed. A nonzero process exit also fails, but exit zero alone never succeeds; the stage's query-backed postcondition must pass.

For an interrupted run:

  1. Do not mark the stage or lifecycle ready manually.
  2. Inspect the latest sanitized reason_code, retry_at, lease expiry, and current fingerprint.
  3. Allow the recovery worker to reclaim only after the lease expires, or fix the terminal prerequisite and enqueue the manifest through the authorized path.
  4. Confirm the old token cannot complete or advance a publication pointer.
  5. Re-run the read-only --plan command and wait for new fenced receipts.

5. Readiness acceptance

Before recurring cutover, all of these must be true:

  • The credential is still verified and not revoked or disabled.
  • Every required stage has current, fingerprint-matched evidence.
  • The console_feed stage published an immutable tenant-keyed version and read it back through the authenticated tenant-scoped consumer path.
  • amazon_recurring_eligibility resolves exactly the intended runtime seller.
  • The independent acceptance suite is green:
python3 -m unittest tests.test_connection_lifecycle_acceptance -v

A zero-sales seller may pass with explicit coverage receipts using queried_zero; zero rows without a request/coverage receipt must remain blocked.

Safe legacy reconciliation

Reconciliation is dry-run by default. It does not infer identity, publish a feed, or mark a run ready:

python3 scripts/reconcile_connection_lifecycle.py \
  > /private/tmp/connection-lifecycle-reconciliation.json

Expected top-level receipt:

{"mode":"dry-run","writeCount":0,"scenarios":[]}

Review every scenario. PartyPrints may use the approved Hemani Noon LLC / PartyPrints mapping. Culinary must remain LEGAL_ENTITY_UNVERIFIED. Keto must remain CREDENTIALS_MISSING. Any other seller requires an authoritative legal entity, brand, and source reference.

Only after migration validation, green independent acceptance, approved diff, and separate production-write authority may the accountable release owner run:

python3 scripts/reconcile_connection_lifecycle.py --apply

Expected receipt: mode=apply; writeCount equals only the previously approved create_manifest_and_queue_run rows; Culinary and Keto remain unchanged. Save the JSON receipt before proceeding. If the observed set differs, roll back the transaction, stop, and investigate; never broaden the mapping in place.

The compatibility bridge is available for one explicit existing seller but is not the normal path:

python3 scripts/activate_company_connection.py \
  --seller <runtime-seller-id> \
  --enqueue-only

It resolves one verified, non-revoked manifest and delegates to the lifecycle. It does not copy credentials or assert readiness.

Revocation and rollback

Revoked, disabled, rotated, reassigned, or materially reconfigured connections must invalidate affected evidence, fence in-flight publication, remove recurring eligibility, and enqueue recovery where appropriate. Never restore eligibility by writing ready, changing a receipt, or setting raw.sellers.is_active alone.

If lifecycle cutover must be rolled back, use the selector rollback in docs/runbooks/nightly-refresh.md. That changes recurring selection only. It does not delete lifecycle data, erase receipts, re-enable a revoked credential, or authorize legacy workers to publish readiness.