# The Stack Weekly, week 46: Patch Better Auth today; the rest of the week deleted code you wrote by hand

> Seven things worth your time from 2 to 8 November 2026. Better Auth shipped twelve security fixes in one day, one of them critical, so upgrade to 1.7.18 before you read anything else. The rest is vendors taking chores off your hands: S3 Tables now migrates Hive tables to Iceberg for you (Sydney included), Durable Objects retry their own failed calls, AI Gateway gets model aliases, CloudWatch takes traces with one header, and a new open-weight decision model and a Claude API beta each solve a smaller problem than their headlines.

- 2–8 November 2026, published 9 November 2026 by Nicolas Dao (Cloudless Labs, Sydney)
- Judged against The Stack: https://cloudlesslabs.com/stack/brief.md
- Web page: https://cloudlesslabs.com/weekly/2026-w46/

## Better Auth 1.7.16 security release, by Better Auth (Vercel)

- Update. Verdict: No change to my pick. Low risk.
- Pain: Your users and sessions live in your own Postgres through Better Auth, which means its bugs are yours to patch. On 3 November twelve of them were published at once, one critical.
- Fix: Upgrade every better-auth and @better-auth/* package to 1.7.18, redeploy, and rotate the app secret if you ever registered the Expo plugin. Neon's managed Better Auth was patched on Neon's side.
- Value: One upgrade and a redeploy close a list of account takeovers. Do it today.
- Company: Better Auth Inc., repository created May 2024, part of Vercel since July 2026
- Product: MIT, about 30,600 GitHub stars; 1.7.13 to 1.7.18 shipped in 11 days; 39 advisories published in 2026
- In The Stack: [Better Auth](https://cloudlesslabs.com/stack/better-auth/index.md), [Neon (serverless Postgres)](https://cloudlesslabs.com/stack/neon/index.md), [Amazon Cognito](https://cloudlesslabs.com/stack/aws-cognito/index.md)

Better Auth is my first pick for serious apps on Postgres because your users live in your own database and cost nothing per user. The price of that is this week: on 3 November the project published twelve advisories at once and shipped the fixes in 1.7.16 (1.8.0-beta.5 on the beta line). One is critical, two are high, eight are medium and one is low. Better Auth's own team says it now runs frontier models over its code for security review, which explains the volume: 39 advisories this year.

**Who is exposed, in plain words.** Most of the twelve only hit you if you turned on the plugin concerned:

- **Critical, CVSS 9.1, `@better-auth/expo`:** a public endpoint would sign any value a caller gave it with the app's secret, the same secret behind email-verification links and the cookie cache. If you ever registered `expo()`, assume someone could have forged a signed value.
- **High, the phone-number plugin:** a number could be claimed before it was verified.
- **High, the Electron plugin:** desktop sign-in could return the auth secret and the social client secrets, and skip two-factor.
- **The ones that hit a plain Postgres app with email and OAuth:** an OAuth provider sending `email_verified` as a string (Cognito's userinfo is the named example) was treated as verified; email-change links stayed valid after the address changed hands; and "sign out everywhere" could miss a session cached in Redis or KV.

**What to do, in order.** Bump `better-auth` and every `@better-auth/*` package to the same version, 1.7.18 (1.7.17 and 1.7.18 fixed more session and Expo state bugs), and redeploy. Then:

- if `expo()` was registered, rotate the app secret, knowing that it logs everyone out;
- if the Electron plugin ever ran, rotate everything, social client secrets included;
- delete phone numbers saved without verification, because the patch doesn't;
- if you use the Stripe plugin, look for Stripe customer ids linked to more than one user;
- add `set-phone` to any custom admin access-control statements, or phone edits break.

Never run anything below 1.7.16.

**Against Cognito.** This is the trade, stated plainly: with Cognito, AWS patches the service and you ship nothing. With Better Auth, you own the library and its Tuesday afternoons. I still take that trade for a serious app, because Cognito's limits (no organisations, a second user store) cost more over a project's life than an upgrade a month. If you want Better Auth without the patching, Neon's managed Better Auth already runs 1.7.16 and needed nothing from its users. That's the strongest argument for it I've seen.

**My verdict: no change to my pick. Upgrade to 1.7.18 today, rotate the secret if you used Expo, and put Better Auth's advisories feed in front of whoever owns your dependencies.**

Sources:

- [Better Auth: security release, 3 November 2026](https://better-auth.com/blog/security-release-2026-11-03)
- [Vercel bulletin: Better Auth November 2026 security release](https://vercel.com/kb/bulletin/better-auth-november-2026-security-release)
- [GitHub: Better Auth security advisories](https://github.com/better-auth/better-auth/security/advisories)
- [GHSA-4wq4-2ppv-q3hg: Expo authorization proxy](https://github.com/better-auth/better-auth/security/advisories/GHSA-4wq4-2ppv-q3hg)
- [Better Auth releases](https://github.com/better-auth/better-auth/releases)
- [Neon changelog](https://neon.com/docs/changelog)

## S3 Tables managed migration from Hive to Iceberg, by AWS

- New. Verdict: Worth a pilot. Medium risk.
- Pain: Your lake is Hive-style Parquet in S3, registered in Glue and queried by Athena: small files pile up, nothing can be updated or deleted, and moving a table to Iceberg means writing a pipeline for it.
- Fix: S3 Tables now runs that migration as a managed job per table, in Sydney too: it copies and compacts into Iceberg while the old table keeps serving, re-syncs changes, and switches over when you say so.
- Value: Iceberg without the migration project, for about 15% more per GB stored.
- Company: AWS, founded 2006
- Product: Available from 4 November 2026 in 10 Regions including ap-southeast-2; S3 Tables itself since December 2024
- In The Stack: [S3 + Glue + Athena](https://cloudlesslabs.com/stack/aws-athena-data-lake/index.md), [DuckDB](https://cloudlesslabs.com/stack/duckdb/index.md)

My [data lake](https://cloudlesslabs.com/stack/aws-athena-data-lake/index.md) is S3, Glue and Athena, and I call it "the lake that works, not amazing". The not-amazing part is Hive-style Parquet: you hand-manage partition folders, small files pile up, nothing can be updated or deleted, and a second way to query the data means a second copy of it. Iceberg fixes most of that, and it's been on my list for months. What stopped me was the migration: one pipeline per table.

**What shipped on 4 November.** S3 Tables now migrates a Glue-registered Hive Parquet table into a managed Iceberg table as a job: Start, then Sync as many times as you like (only changes are copied), then Complete, when the new table becomes writable. The old table keeps serving the whole time. On the way it converts types, recompresses Snappy to ZSTD and compacts small files to 512 MB. It's in 10 Regions at launch, **Sydney included**.

**What it costs in Sydney.**

| | Plain S3 + Glue | S3 Tables (Iceberg) |
|---|---|---|
| Storage | $0.025/GB-month | $0.0288/GB-month |
| Per-object monitoring | none | $0.025 per 1,000 objects a month |
| Compaction | yours to build | $0.005/GB |
| 1 TB a month, my arithmetic | about $25.60 | about $29.50 |

The conversion itself is free: you pay for the data copied, and $2 per million source objects on each sync. The trap is the monitoring fee on a table of tiny files: a million objects cost $25 a month, as much as the data. Compaction should bring that count down, but count your objects before you start; the compatibility report lists every one.

**Gotchas, each with its fix.**
- **Lake Formation tables aren't supported.** Check which databases are governed before you plan.
- **Same account and Region, Parquet only.** ORC, Avro, JSON and Hive ACID tables need an Athena CTAS first.
- **A sync fails any source object that was overwritten.** Keep writes append-only during the migration.
- **Your partitioning comes across as it is.** The second-index pain needs a second step: partition transforms such as `day(ts)` and `bucket(N, id)`, and sort or z-order compaction.
- **Writers must move at the end.** Sync, pause writers briefly, sync once more, Complete, then point Athena and your jobs at the table bucket.

DuckDB, which I pair with Athena, reads S3 Tables through `ATTACH … ENDPOINT_TYPE s3_tables`, so the laptop half of my setup survives. IaC creates the table bucket, namespace and role; the migration itself is a CLI or SDK call, which is right for a one-off job.

This is how I'd run it for a client: one table that hurts, not the crown jewels, synced for a week next to the old one, with Athena queries compared on both before anyone flips a writer.

**My verdict: worth a pilot on one non-critical table. It removes the migration project that kept me on Hive, in Sydney, for about 15% more storage.**

Sources:

- [AWS What's New: S3 Tables managed migration from Hive to Iceberg](https://aws.amazon.com/about-aws/whats-new/2026/11/amazon-s3-tables-managed-migration-hive-to-iceberg/)
- [AWS News Blog: managed migration of Apache Hive tables](https://aws.amazon.com/blogs/aws/amazon-s3-tables-now-offer-managed-migration-of-apache-hive-tables-to-apache-iceberg/)
- [S3 Tables migration: setting up and limitations](https://docs.aws.amazon.com/AmazonS3/latest/userguide/s3-tables-migrate-setting-up.html)
- [S3 Tables migration: how it works](https://docs.aws.amazon.com/AmazonS3/latest/userguide/s3-tables-migrate-how-it-works.html)
- [S3 pricing](https://aws.amazon.com/s3/pricing/)
- [DuckDB: Iceberg catalogs](https://duckdb.org/docs/2.0/core_extensions/iceberg/catalogs.html)

## Sarvam Prism, and Perplexity's decisions that search the web, by Sarvam AI and Perplexity

- Follow-up. Verdict: Watching. High risk.
- Pain: The yes, no or label step in your product runs on an LLM prompt: the answer is text to parse, it can flip when you reorder the options, and its confidence is useless for "act above 90%".
- Fix: Two more decision models answer with a probability per option: Sarvam's Prism, with Apache 2.0 weights, and Perplexity's Decisions API, which can now search the web before it answers.
- Value: More choice and a second open-weight exit, but Baseten stays my pick.
- Company: Sarvam AI, founded 2023; Perplexity, founded 2022
- Product: Prism GA on Sarvam's API with open weights from 3 November 2026; Perplexity Decisions API from October 2026, web grounding from November 2026
- In The Stack: [Baseten decision models](https://cloudlesslabs.com/stack/baseten-decision-models/index.md), [Jev](https://cloudlesslabs.com/stack/typesafe-jev/index.md), [Cloudflare Workers AI](https://cloudlesslabs.com/stack/cloudflare-workers-ai/index.md)

Decision models, which return a probability per option instead of a paragraph, are the paradigm shift I keep pointing at: they make AI reliable in software without paying for more intelligence. Last week's edition showed them reading images. This week the field got wider.

**Sarvam Prism (3 November).** An Indian lab's decision model, a LoRA on its 105B model, with **Apache 2.0 weights**. You send a state and typed questions (yes or no, pick one, a score) and get a probability for each answer in one pass, timed by Sarvam at 44 ms on a B200. Sarvam claims the answer never flips when you shuffle the options, which is exactly the bug that makes prompted labels untrustworthy. On Sarvam's own average of three indices it scores 71.8, ahead of Perplexity's Decider v1.2 at 68.0 and Jev 1.14 at 64.5. Baseten's models, my pick, aren't in that table, so there's no like-for-like comparison yet.

The catch is size. Hosted, it's ₹4 per million input tokens with free output, about $0.045 by my conversion, on Sarvam's API only, with no stated region or retention terms. Self-hosted, you're running the whole 105B base: about 106 GB of weights on one 120 GB FP8 GPU such as a B200 or H200, loaded with Sarvam's own script, not vLLM. For an Australian client that's a dedicated, scarce GPU for a classifier. Baseten's MIT weights on a [Sydney GPU](https://cloudlesslabs.com/stack/aws-sagemaker/index.md) remain the realistic way to keep a decision in Australia.

**Perplexity's Decisions API can now search before it decides.** Its `web_grounding` mode runs a search per question and returns the results it used, so a decision can rest on facts newer than the model, at $0.02 per million tokens for Decider v1.2 plus $0.001 per search. That's useful for "is this claim still true?" and dangerous for anything confidential: the question text goes to a web search. Never ground a question that contains client data.

**The honest numbers from the field.** Hightouch tested the design I'd recommend, a cheap decision model first and Opus only for the doubtful middle, and the headline says "over 4x cheaper". On its harder test it's 1.8x, on synthetic data, with thresholds tuned on the same set. Still a real saving, and still the right shape: let the decision model take the confident majority (78% in Hightouch's test) and pay for intelligence on the rest. Google's developer blog showed the same idea routing coding tasks between Gemini tiers with Jev, on a single run of 50 prompts.

When Microsoft, OpenAI, Perplexity and now Sarvam all ship the same new kind of model within six weeks, the idea is real. What isn't settled is who wins, and self-reported tables don't settle it.

**My verdict: watching Prism, a real open-weight option with only its maker's numbers behind it. No change to my pick: Baseten for production, Jev to play with. Run your own labelled cases through all three before you believe any league table.**

Sources:

- [Sarvam: Prism](https://www.sarvam.ai/blogs/sarvam-prism)
- [Sarvam API: Prism](https://docs.sarvam.ai/api/token-factory/models/sarvam-prism)
- [Hugging Face: sarvamai/prism](https://huggingface.co/sarvamai/prism)
- [Perplexity API changelog](https://docs.perplexity.ai/docs/resources/changelog.md)
- [Perplexity API pricing](https://docs.perplexity.ai/docs/getting-started/pricing.md)
- [Hightouch: LLM judges for identity resolution](https://hightouch.com/blog/llm-judges-identity-resolution)
- [Google Developers Blog: cheap classifiers to route across Gemini models](https://developers.googleblog.com/cost-per-task-using-cheap-classifiers-to-route-across-gemini-models-and-thinking-levels/)

## AI Gateway model aliases, and authentication you can't turn off, by Cloudflare

- Update. Verdict: No change to my pick. Low risk.
- Pain: The model id is hard-coded in your app, so changing models or adding a fallback is a code change and a redeploy, and Workers AI retires 16 models on 20 November whether you're ready or not.
- Fix: AI Gateway aliases give a pool of models one name, with ordered fallback or smart routing, edited in the dashboard or API. New gateways must also require a Cloudflare token, permanently.
- Value: Swap or fall back models without a deploy. Free.
- Company: Cloudflare, founded 2009
- Product: Aliases from 4 November 2026, no stage label; required authentication on new gateways from 3 November
- In The Stack: [Cloudflare AI Gateway](https://cloudlesslabs.com/stack/cloudflare-ai-gateway/index.md), [OpenRouter](https://cloudlesslabs.com/stack/openrouter/index.md), [Cloudflare Workers AI](https://cloudlesslabs.com/stack/cloudflare-workers-ai/index.md)

I keep [AI Gateway](https://cloudlesslabs.com/stack/cloudflare-ai-gateway/index.md) on my watch list as the free layer in front of [OpenRouter](https://cloudlesslabs.com/stack/openrouter/index.md): caching, rate limits, spend caps, fallback, even from Lambda. Two changes this week make it more useful and slightly more work.

**Aliases (4 November).** An alias is a nickname for a list of models. Your code calls `custom/support-fast`; the gateway tries the first model in the list and moves down it on failure, or picks one per request in smart mode. You edit the list in the dashboard or the API, and the app never redeploys. Up to 100 aliases per gateway, 1 to 50 models each, all speaking the same request format. Core features cost nothing.

The timing matters: **Workers AI retires 16 models on 20 November** and answers HTTP 410 from then on. If an id like `deepseek-v4-pro-0813` is hard-coded in a Lambda today, that's a deploy under pressure. With an alias, it's a dashboard edit. Put a model that isn't on Workers AI last in every pool, so a retirement can never take the whole alias down.

**Authentication you can't turn off (3 November).** Every new gateway must require a Cloudflare API token, and the setting can't be disabled afterwards. Before, an open gateway answered anyone who knew the account and gateway ids. Existing gateways are unchanged. This is the right default, with one sharp edge: the "AI Gateway Run" permission is **account-wide**, so one token reaches every gateway and every stored provider key. Keep it server-side, in Secrets Manager for a Lambda, and if two clients must never share keys, give them two Cloudflare accounts.

**Gotchas.** Aliases are documented on the REST path, `api.cloudflare.com/…/ai/run` with `Authorization: Bearer` and a `cf-aig-gateway-id` header, while provider-native URLs on `gateway.ai.cloudflare.com` take `cf-aig-authorization`. Don't assume aliases work on the OpenAI-compatible endpoint until you've tested it. Alias edits propagate with a delay, so a switch isn't instant in an incident. And Pulumi and Terraform manage the gateway and its authentication but not aliases, which live in the API for now.

**Against OpenRouter.** The two stack rather than compete: alias, then OpenRouter model, then provider. OpenRouter's rebuilt Auto Router (also this week) picks a model for you on its own scoring; Cloudflare's alias picks from a list you wrote. I prefer the list I wrote.

**My verdict: no change, still watching, but this is the week to move hard-coded model ids behind an alias, before 20 November does it for you.**

Sources:

- [Cloudflare changelog: model aliases in AI Gateway](https://developers.cloudflare.com/changelog/post/2026-11-04-model-aliases/)
- [AI Gateway docs: model aliases](https://developers.cloudflare.com/ai-gateway/features/routing/model-aliases/)
- [Cloudflare changelog: new AI Gateways require authentication](https://developers.cloudflare.com/changelog/post/2026-11-03-required-authentication/)
- [AI Gateway docs: authenticated gateway](https://developers.cloudflare.com/ai-gateway/configuration/authentication/)
- [Cloudflare changelog: Workers AI planned model deprecations](https://developers.cloudflare.com/changelog/post/2026-11-05-planned-model-deprecations/)
- [OpenRouter: Auto and Auto Code routers](https://openrouter.ai/blog/announcements/auto-and-auto-code-routers/)

## Durable Objects retry their own failed calls, by Cloudflare

- Update. Verdict: No change to my pick. Low risk.
- Pain: Every Worker that calls a Durable Object carries a retry loop for "object restarting" errors, and when the connection drops mid-call, a retry can run the method twice.
- Fix: The runtime now retries calls that fail before reaching the object, up to four times in 10 seconds, and refuses a duplicate if the first attempt landed. Mark idempotent methods retryable() to allow a re-run.
- Value: Delete your retry loop, or at least shrink it.
- Company: Cloudflare, founded 2009
- Product: On by default from 5 November 2026, no flag; retryable() and the retry option need Wrangler 4.158.0 or later
- In The Stack: [Cloudflare Durable Objects](https://cloudlesslabs.com/stack/cloudflare-durable-objects/index.md), [Cloudflare Workers](https://cloudlesslabs.com/stack/cloudflare-workers/index.md)

[Durable Objects](https://cloudlesslabs.com/stack/cloudflare-durable-objects/index.md) are my referee for live, shared state, and the code that calls them has always carried a little tax: a retry loop with backoff for "object restarting" and "moved machine" errors, plus a nagging doubt. When a connection drops mid-call, did the method run or not? Retry, and you might add the item to the cart twice.

**What changed on 5 November.** The runtime now retries a call that fails before it reaches the object: up to four more attempts within 10 seconds, with backoff and jitter, on by default with no flag. For the dropped-connection case, the retry carries the same request identity and the object refuses it if the first attempt arrived. So the default is "retry, but never twice". If a method is idempotent, setting a quantity rather than adding one, you can mark it with `retryable()` from `cloudflare:durable-objects`, and then it may run again. Per stub, `retry: { maxRetries, timeoutMs }` tunes or disables it. You need Wrangler 4.158.0 or later for the new API; the default needs nothing.

**What it doesn't retry:** errors your own code throws, `overloaded` errors (rightly: retrying an overloaded object makes it worse), HTTP 500s, calls with streams, pipelined calls and stubs you received over RPC. If those matter, they're still yours.

This connects to last week's item: deploys now [defer code updates](https://cloudlesslabs.com/weekly/2026-w45/index.md), and calls that hit an object mid-restart now retry by themselves. Deploying a Worker full of Durable Objects is quietly becoming a non-event.

**Gotchas, each with its fix.**
- **Your loop stacks on theirs.** Three attempts of yours become fifteen. Set `maxRetries: 0` on stubs where you keep a loop, or cut your loop down.
- **`retryable()` on the wrong method doubles a side effect.** Only mark methods that set absolute values or check an idempotency key stored in the object.
- **A method that called an outside API, then lost the connection,** will call it again if it's marked retryable. Pass that API an idempotency key.
- **Ten seconds is the window.** For work that must survive minutes, use an alarm or a queue, not a retry.

Billing for retried attempts isn't stated on the pricing page. At $0.15 per million requests after the first million, it won't matter unless something retries in a storm, and then you have a bigger problem.

On AWS, the closest equivalent is SQS redelivery, which promises at-least-once and makes every handler prove it's idempotent. Cloudflare took the other side: retry only what never arrived, and block the duplicate. For a referee, that's the right side.

**My verdict: no change to my pick, one less thing to write. Remove or shrink your retry loops, and mark only truly idempotent methods.**

Sources:

- [Cloudflare changelog: automatic retries for Durable Object calls](https://developers.cloudflare.com/changelog/post/2026-11-05-durable-objects-automatic-retries/)
- [Durable Objects: automatic retries](https://developers.cloudflare.com/durable-objects/best-practices/automatic-retries/)
- [Durable Objects: error handling](https://developers.cloudflare.com/durable-objects/best-practices/error-handling/)
- [Durable Objects pricing](https://developers.cloudflare.com/durable-objects/platform/pricing/)

## CloudWatch takes OpenTelemetry traces with an API key, by AWS

- New. Verdict: Worth a pilot. Medium risk.
- Pain: Your Worker, CI job or SaaS outside AWS can't send traces to CloudWatch without SigV4 signing, so you run a collector or a signing proxy, or store AWS access keys at the edge.
- Fix: The X-Ray OTLP endpoint now accepts a bearer API key that can only write spans: one Authorization header from any OTLP/HTTP exporter, in Sydney too.
- Value: One header replaces a collector, for traces only.
- Company: AWS, founded 2006
- Product: GA from 3 November 2026 in every commercial Region with the X-Ray OTLP endpoint, Sydney and Melbourne included
- In The Stack: [Amazon CloudWatch](https://cloudlesslabs.com/stack/aws-cloudwatch/index.md), [Cloudflare Workers](https://cloudlesslabs.com/stack/cloudflare-workers/index.md), [Amazon Data Firehose](https://cloudlesslabs.com/stack/aws-firehose/index.md)

My stack puts [Workers](https://cloudlesslabs.com/stack/cloudflare-workers/index.md) at the edge and the business logic on AWS, and tracing across that line has been ugly. CloudWatch only took OpenTelemetry traces signed with SigV4, so a Worker, a CI job or a SaaS webhook needed a collector, a signing proxy, or AWS access keys stored at the edge. All three are worse than the problem they solve.

**What shipped on 3 November.** The X-Ray OTLP traces endpoint now accepts an API key in an `Authorization: Bearer` header. The key is an IAM service-specific credential for `xray.amazonaws.com`: it belongs to an IAM user, it can only write spans to `/v1/traces`, and it can't read anything or call any other API. Each IAM user holds two, so you rotate without downtime, and revoking takes about 5 minutes. It's GA in every commercial Region with the endpoint, **Sydney and Melbourne included**. Cloudflare's Workers can already export traces to an OTLP destination with custom headers, in JSON, which X-Ray accepts, so in principle a Worker can now post spans straight to `xray.ap-southeast-2.amazonaws.com`. Send a test span before you trust it.

**What it isn't.** Traces only: there's no bearer option for OTLP logs or metrics, so my logs advice stands (CloudWatch for what you alarm on, [Firehose](https://cloudlesslabs.com/stack/aws-firehose/index.md) to S3 for the chatty bulk). Transaction Search must be on first, and spans are billed as its ingestion, $0.35 per GB in us-east-1; the pricing page doesn't publish the Sydney rate. AWS itself still recommends SigV4 with short-lived credentials where you can sign. That's correct: this is for the places you can't.

**The risk is the key itself.** It's long-lived and static, and **it never expires unless you say so**. A leaked key lets anyone push spans into your account and run up the ingestion bill. So:
- create it with `--credential-age-days` and enforce a maximum with an IAM condition or an SCP;
- one IAM user per integration, so one leak is one revocation;
- store it as a Worker secret or in Secrets Manager at creation, because it can't be read back;
- alarm on CloudTrail events for bearer-token calls.

Creating it through Terraform puts the secret in state, and the provider has an open issue on that resource, so I'd create it with the CLI and keep only the IAM user in code.

**My verdict: worth a pilot for anything outside AWS that should trace into CloudWatch. Medium risk, all of it in how you handle a static key.**

Sources:

- [AWS What's New: CloudWatch API keys for OpenTelemetry](https://aws.amazon.com/about-aws/whats-new/2026/11/amazon-cloudwatch-api-keys-opentelemetry/)
- [X-Ray docs: bearer token authentication for OTLP](https://docs.aws.amazon.com/xray/latest/devguide/xray-opentelemetry-bearer-token.html)
- [CloudWatch pricing](https://aws.amazon.com/cloudwatch/pricing/)
- [Cloudflare Workers: exporting OpenTelemetry data](https://developers.cloudflare.com/workers/observability/exporting-opentelemetry-data/)
- [Terraform AWS provider issue 47421](https://github.com/hashicorp/terraform-provider-aws/issues/47421)

## Claude API message threads (beta), by Anthropic

- New. Verdict: Watching. Medium risk.
- Pain: Your agent on Lambda uploads its whole history, 150K tokens of JSON, on every turn, and time to first token grows as the session does.
- Fix: Message threads keep the conversation on Anthropic's side, so each turn sends only the new messages. It saves bandwidth and latency, not tokens, and a thread dies after 5 idle minutes.
- Value: Faster long sessions on the Claude API, at the same token bill.
- Company: Anthropic
- Product: Beta from 2 November 2026 (header message-threads-2026-08-12); Claude API, Claude Platform on AWS, Google Cloud and Foundry; not Bedrock or OpenRouter
- In The Stack: [Anthropic API (for client systems)](https://cloudlesslabs.com/stack/anthropic-api/index.md), [Amazon Bedrock](https://cloudlesslabs.com/stack/aws-bedrock/index.md), [OpenRouter](https://cloudlesslabs.com/stack/openrouter/index.md)

A long-running agent on Lambda has a silly cost: every turn uploads the entire conversation again. At 40 turns and 150K tokens of history, that's a big JSON body that the API re-validates and re-tokenizes each time, and time to first token grows with the session. Prompt caching already cut the token bill on those old turns; it never cut the upload.

**What shipped on 2 November, as a beta.** Message threads keep the conversation on Anthropic's side. The first request creates a thread with the full history, system prompt and tools; each later request sends only the new messages plus the previous message id. The request stays a few KB however long the session gets.

**What it doesn't do, which the headlines skip.** It doesn't save tokens: Anthropic says plainly that threads change neither prices nor rate limits, and caching inside a thread still needs `cache_control`. You pay the same, and get the answer sooner. And it's fragile by design:
- **a thread expires 5 minutes after its last request**, and lives an hour at most. After that, a continue returns 404 `thread_not_found` and you resend everything;
- each message id can be continued once, so concurrent invocations on the same session collide;
- the system prompt, tools and model are fixed when the thread is created;
- ZDR and HIPAA organisations can't use it at all, and compaction, Batches and token counting don't work with it.

On Lambda, that means you still keep the full history yourself, in DynamoDB or S3, plus the last message id per session, and you serialise turns per session. The thread is an optimisation on top of a design that works without it.

**Where it runs, and where it doesn't.** The Claude API, Claude Platform on AWS, Google Cloud and Foundry. **Not Bedrock, and not OpenRouter**, which are the two routes I'd actually use for a client: [Bedrock](https://cloudlesslabs.com/stack/aws-bedrock/index.md) because it keeps Claude's data in Australia, OpenRouter because it fails over across providers. A thread fails over nowhere. OpenAI's equivalent, `previous_response_id`, survives idle gaps because it stores responses for 30 days by default, which is the opposite trade on retention.

**My verdict: watching. A real latency win for very long sessions on Anthropic's own API, with no saving on the bill and no Australian route. Come back when it reaches Bedrock.**

Sources:

- [Claude API release notes](https://platform.claude.com/docs/en/release-notes/api)
- [Claude docs: message threads](https://platform.claude.com/docs/en/build-with-claude/message-threads)
- [Claude docs: Claude Platform on AWS](https://platform.claude.com/docs/en/build-with-claude/claude-platform-on-aws)
- [OpenAI docs: conversation state](https://developers.openai.com/api/docs/guides/conversation-state)

## Looked at, skipped

- [Lambda queue mode for Kafka event sources](https://aws.amazon.com/about-aws/whats-new/2026/11/aws-lambda-queue-kafka-esm/) (AWS): Lambda can finally consume Kafka like a queue, past one invocation per partition, but only on self-managed Kafka 4.2 or Confluent Cloud: MSK doesn't support it yet, and running Kafka yourself is a skip in my stack. If you just need a work queue in front of Lambda, it's still SQS.
- [Lambda durable functions get 5 to 10 times higher default quotas](https://aws.amazon.com/about-aws/whats-new/2026/11/lambda-durable-functions-default-quotas/) (AWS): Good to know, not an item: running executions go from 1 million to 5 million, but nobody I work with hit the old ceiling, and Sydney gets the base numbers while three US and EU Regions get double.
- [Workers AI retires 16 models on 20 November](https://developers.cloudflare.com/changelog/post/2026-11-05-planned-model-deprecations/) (Cloudflare): Moved from 15 to 20 November, after which the old ids return HTTP 410. Check your code and any AI Gateway alias for kimi-k2.6, glm-5.3-flash and deepseek-v4-pro-0813 now; the churn is one more reason Workers AI stays a skip.
- [Node.js security release on 11 November](https://nodejs.org/en/blog/vulnerability/november-2026-security-releases) (Node.js): Only a pre-announcement, with the highest severity HIGH and no details yet, for 26.x, 24.x and 22.x. Book the time to redeploy your Lambdas on Wednesday; the item comes once there's something to patch.
- [OpenRouter's rebuilt Auto Router and Auto Code](https://openrouter.ai/blog/announcements/auto-and-auto-code-routers/) (OpenRouter): No router fee, and a 74% saving measured by OpenRouter on OpenRouter's benchmarks. I don't let a vendor pick my model on its own numbers; pin the model and test the router on your own tasks.
- [Amazon SES in Melbourne and New Zealand](https://aws.amazon.com/about-aws/whats-new/2026/11/amazon-simple-email-service-new-aws-regions/) (AWS): A second Australian Region for email, useful for disaster recovery, but Sydney already kept the data in-country, and each new Region still means leaving the sandbox again.
- [Kimi K3.1 Pro open weights, and on Bedrock](https://huggingface.co/moonshotai/Kimi-K3.1-Pro) (Moonshot AI): The weights are out and Bedrock serves it, but it scores 46 on the index for $3.68 a task, while GPT-6.1 Sol scores 55 for $1.27. Below the frontier and dearer per task than what beats it.
- [Gemini 4 Argon's cost per task rises](https://artificialanalysis.ai/leaderboards/models) (Google): Same score of 50, now $9.95 a task instead of $7.68, and a secondary site says the introductory price ends on 30 November. A frontier model getting dearer is the opposite of news I act on: wait for Google's own page.
- [Cognito Plus gets a 99.99% SLA](https://aws.amazon.com/about-aws/whats-new/2026/11/amazon-cognito-sla-update/) (AWS): Only on the paid Plus plan; the free tier I recommend for small apps stays at 99.9%, which is fine for an admin panel.
- [Render Sandboxes, Workflows and Shared Filesystems](https://finance.yahoo.com/technology/ai/articles/render-expands-platform-simplify-running-140000257.html) (Render): Another place for agents to run untrusted code, outside the client's AWS account, announced through a press release with no price I could check. Cloudflare Sandbox already does this job for me.
- [PagerDuty's Paige, an "AI SRE"](https://siliconangle.com/2026/11/03/pagerduty-debuts-paige-ai-agent-with-renamed-pd-reliability-platform-and-pd-labs/) (PagerDuty): A product rename and an agent with a person's name, announced by press release. Innovation circus until someone shows the incidents it closed on its own.
- [Claude Code security leads (email in the User-Agent, saved passwords in "Don't Ask Again" rules)](https://github.com/anthropics/claude-code/issues/107757) (Anthropic): Both came through Hacker News and neither has a primary answer yet, so no item. Meanwhile, check that your committed .claude/settings.json files hold no credentials: that part needs no confirmation.
- [Cursor deploys the apps its agents build](https://thenewstack.io/cursor-ai-app-deployment/) (Cursor (Anysphere)): An editor that provisions your database, logins and hosting is a lock-in with a nice demo. I want the infrastructure in the client's account, in code, not in my editor's.
- [OpenAI buys Pierre Computer, Meta buys Conductor](https://techcrunch.com/2026/11/04/meta-acquires-ai-coding-startup-conductor/) (OpenAI and Meta): Acquisitions with no product change for anyone this week. Agent orchestration is consolidating; that's all it tells you.
- [Restate durable coroutines](https://restate.dev/blog/durable_coroutines) (Restate): A neat model with vendor latency numbers measured on another cloud. For durable steps inside AWS, Lambda durable functions are already on my watch list and run in the client's account.

## For the geeks

### Better Auth: upgrade every package together

```bash
# All better-auth packages on the same fixed version (1.7.16 is the minimum)
npm install better-auth@1.7.18 @better-auth/expo@1.7.18 @better-auth/electron@1.7.18
npm ls | grep better-auth   # every line should say 1.7.18
```

Source: [Better Auth security release](https://better-auth.com/blog/security-release-2026-11-03). Install only the plugins you use.

### S3 Tables: start a migration (trimmed from AWS's example)

```bash
aws s3tables start-table-migration --cli-input-json file://start-migration.json
# start-migration.json
{
  "roleARN": "arn:aws:iam::123456789012:role/S3TablesMigrationRole",
  "destinationTable": {
    "tableBucketARN": "arn:aws:s3tables:ap-southeast-2:123456789012:bucket/my-destination-bucket",
    "namespace": "mynamespace",
    "name": "my_destination_table",
    "properties": { "writeFormat": "parquet", "icebergFormatVersion": 2, "compressionCodec": "zstd" }
  },
  "sourceType": "glueTable",
  "source": { "glueTable": { "catalogId": "123456789012", "databaseName": "my_glue_database", "tableName": "my_source_table" } },
  "dataMigration": {
    "maintenanceSettings": { "icebergCompaction": { "targetFileSizeMB": 512, "strategy": "binpack" } },
    "migrationPolicies": { "unmatchedSourceFieldsPolicy": "fail", "incompatibleValuesPolicy": "fail" }
  },
  "migrationOutput": { "bucket": "arn:aws:s3:::my-report-bucket", "prefixes": { "tableCompatibilityReport": "reports/table-compatibility/" } }
}
# then sync-table-migration (repeat), and complete-table-migration when writers are paused
```

Source: [AWS News Blog](https://aws.amazon.com/blogs/aws/amazon-s3-tables-now-offer-managed-migration-of-apache-hive-tables-to-apache-iceberg/).

### Sarvam Prism: one decision, acted on above a threshold

```python
from sarvamai import SarvamAI

client = SarvamAI(api_subscription_key="YOUR_SARVAM_API_KEY")
result = client.decisions.create(
    model="sarvam-prism",
    state="Checkout payments have been failing since the last Stripe update.",
    questions={
        "is_critical": {"type": "noul", "instructions": "Does this issue block revenue right now?"},
        "owner": {"type": "choice", "instructions": "Which team should take this?",
                  "criteria": {"billing": "Payment or invoice problems",
                               "engineering": "Bugs or service outages",
                               "sales": "Pre-sale questions"}},
    },
)
answers = result.answers
if answers["is_critical"].noul >= 0.9:
    print("Route to", answers["owner"].choice)
else:
    print("Send to a human for review")
```

Source: [Sarvam API docs](https://docs.sarvam.ai/api/token-factory/models/sarvam-prism), shortened.

### AI Gateway: call an alias from a Lambda

```javascript
// Node 20+. The fetch translation of Cloudflare's curl example is mine.
const url = `https://api.cloudflare.com/client/v4/accounts/${process.env.CF_ACCOUNT_ID}/ai/run`;
const res = await fetch(url, {
  method: 'POST',
  headers: {
    'Authorization': `Bearer ${process.env.CF_API_TOKEN}`, // from Secrets Manager, never in code
    'Content-Type': 'application/json',
    'cf-aig-gateway-id': 'my-gateway',
  },
  body: JSON.stringify({ model: 'custom/support-fast', input: { messages: [{ role: 'user', content: 'Hello' }] } }),
});
const data = await res.json();
```

Source: [AI Gateway model aliases](https://developers.cloudflare.com/ai-gateway/features/routing/model-aliases/).

### Durable Objects: mark only the idempotent method

```javascript
import { DurableObject } from "cloudflare:workers";
import { retryable } from "cloudflare:durable-objects";

export class Cart extends DurableObject {
  static {
    retryable(this.prototype.setQuantity);
  }
  // Idempotent: a second run sets the same quantity.
  async setQuantity(itemId, quantity) {
    await this.ctx.storage.put(itemId, quantity);
  }
  // Not retryable: a second run would add another item.
  async addOne(itemId) {
    const quantity = (await this.ctx.storage.get(itemId)) ?? 0;
    await this.ctx.storage.put(itemId, quantity + 1);
  }
}

// Caller, optional tuning:
// env.CART.getByName("user-123", { retry: { maxRetries: 1, timeoutMs: 2000 } })
```

Source: [Durable Objects automatic retries](https://developers.cloudflare.com/durable-objects/best-practices/automatic-retries/).

### CloudWatch: a key that expires, and a span with one header

```bash
# One IAM user per integration; the key expires in 90 days
aws iam create-service-specific-credential \
  --user-name worker-traces --service-name xray.amazonaws.com --credential-age-days 90

curl -X POST "https://xray.ap-southeast-2.amazonaws.com/v1/traces" \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer ${XRAY_API_KEY}" \
  -d @spans.json
```

Source: [X-Ray bearer token authentication](https://docs.aws.amazon.com/xray/latest/devguide/xray-opentelemetry-bearer-token.html).

### Claude message threads: create, then continue

```bash
# Turn 1: the full conversation, creating a thread
curl -sS https://api.anthropic.com/v1/messages \
  -H "x-api-key: $ANTHROPIC_API_KEY" -H "anthropic-version: 2026-10-21" \
  -H "anthropic-beta: message-threads-2026-08-12" -H "content-type: application/json" \
  -d '{"model":"claude-opus-5-5","max_tokens":1024,"cache_control":{"type":"ephemeral"},
       "system":"You are a support agent for Acme. Keep replies short.",
       "messages":[{"role":"user","content":"Hi! I have a question about an order."}],
       "thread":{"type":"create"}}'
# Turn 2: only the new message; on 404 thread_not_found, resend everything with "create"
curl -sS https://api.anthropic.com/v1/messages \
  -H "x-api-key: $ANTHROPIC_API_KEY" -H "anthropic-version: 2026-10-21" \
  -H "anthropic-beta: message-threads-2026-08-12" -H "content-type: application/json" \
  -d '{"model":"claude-opus-5-5","max_tokens":1024,"cache_control":{"type":"ephemeral"},
       "messages":[{"role":"user","content":"How long does standard shipping usually take?"}],
       "thread":{"type":"continue","previous_message_id":"'"$message_id"'"}}'
```

Source: [Claude docs: message threads](https://platform.claude.com/docs/en/build-with-claude/message-threads).

## Coverage

Window 2 to 8 November 2026 (UTC). Scanned the AWS What's New and News Blog feeds (nothing dated 7 or 8 November), the Cloudflare changelog and blog, InfoQ, Hacker News, the release notes and advisories of the tools in the stack, X and Google News, the week's new models on OpenRouter, Hugging Face and Workers AI, the Artificial Analysis leaderboard, every topic past editions covered, plus open searches across every concern in the catalog. No model in the top ten of the index got cheaper this week: the OpenRouter "drops" were hosts moving, not vendors cutting. Several X posts and the openai.com pages refused to load, so they counted only when a primary page backed them. Not exhaustive: if it matters and it's missing, tell me.

## Related

- [Every edition of The Stack Weekly](https://cloudlesslabs.com/weekly/index.md): newest first, with summaries
- [The Stack, in one file](https://cloudlesslabs.com/stack/brief.md): the catalog these items are judged against
- [Map of every Markdown file on cloudlesslabs.com, with what each one answers](https://ask.cloudlesslabs.com)
