Zod-contract : OpenAPI without the wrapper


TL;DR

  • v0.4 ships as five focused npm packages under the @aemrezorlu/zod-contract umbrella. Not one, because the problem doesn’t fit in one.
  • Core CLI gains init and --exclude. Three collision modes land too: error, merge, first-wins.
  • Bidirectional $ref works via z.lazy(). Every other library breaks this.
  • tRPC subscriptions land in OpenAPI 3.2 webhooks:, the only native place for them.
  • @aemrezorlu/zod-contract-auth v0.1.0 debuts. Security schemes, per-operation security:, public-route allowlists.
  • Roadmap through v0.5: watch deletion, zod-contract validate, structured errors. Plus OAuth2/OIDC, Fastify/Express adapters, a Drizzle → Zod bridge.

The problem: every OpenAPI generator wants you to wrap

Most Zod → OpenAPI tools force the same wrapping ritual:

const User = z.object({...}).openapi('User')  // the contract gets a name
const Foo  = z.object({...}).openapi('Foo')   // by hand, twice, per file

You do it once, fine. You do it on a 200-schema codebase and you start hating it. Worse: every time you forget, the schema silently appears in the output as anonymous. $ref breaks. Debugging gets harder. Your contract drifts away from what the code does.

zod-contract’s position: the export name IS the contract. export const User = z.object({...}) is enough. No .openapi() ceremony.

The first version of this project shipped in a weekend and lived a year. The things people still ask for are the ones that only matter once you cross 50 schemas. Bidirectional refs. Validation against the generated output. An init that doesn’t make you copy-paste from a README. v0.4 is where those land.


Why five packages (and not one meg-plugin)

A Hono plugin is not a tRPC plugin. An auth plugin is not a routing plugin. Trying to merge them is how you ship a meg-plugin nobody trusts.

The v0.1 era of this project (yes, there were 0.x experiments) was one big repo. Every new routing framework meant a feature branch that broke the existing tests. Every new auth flavor meant a coupling that didn’t belong there.

v0.3+ split the boundary:

Package Role
@aemrezorlu/zod-contract Zod introspection → OpenAPI components + JSON examples
@aemrezorlu/zod-contract-paths File-based routing (e.g. users.post.ts → POST /users)
@aemrezorlu/zod-contract-hono Walks a Hono app.routes table, supports inline zValidator() via AST
@aemrezorlu/zod-contract-trpc Walks a tRPC appRouter._def.procedures, splits subscriptions into webhooks: on 3.2
@aemrezorlu/zod-contract-auth Emits components/securitySchemes + per-operation security:

Each package gets its own peer-deps range. Its own semver. Its own changelog. When you don’t need auth, you don’t import it. When your router changes, you only bump the routing plugin.

The peer-dep discipline this enforces is not free. It’s the cycle’s most underrated chore (more on that below). It pays back when a Hono user upgrades without dragging tRPC changes along, and vice versa.


What’s in v0.4

Core, zod-contract 0.4.0

  • zod-contract init [dir] scaffolds src/schemas/User.ts with a working starter, idempotent by default. Add --with-package-scripts and it injects zod-contract:build plus zod-contract:watch into package.json. Only if absent. It never overwrites anything you’ve already set.
  • --exclude <glob...> filters source files during scan. Supports **, *, ?. Real-world pattern:
    zod-contract build src/api api \
      --exclude '**/internal/**' '**/*.draft.ts'
  • --on-collision <mode> controls behavior when two exports share a name across files:
    Mode Behavior
    first-wins (default) Keep the first occurrence, stderr note
    error Throw, refuse to build
    merge Combine ZodObject shapes via Zod.merge() (last-wins per key); non-ZodObject collisions throw with a clear “rename one” pointer
  • Bidirectional $ref via z.lazy() is the cycle that every other library silently breaks. User → Address → User now emits $ref on both sides. The recursion goes through the walking set in convert(). (This was actually v0.3.0 but worth surfacing. Most users hit it on day one.)

Routing plugins, paths 0.4.1, hono 0.3.1, trpc 0.3.1

All three shipped peer-dep bumps to ^0.4.0. Beyond that:

  • paths 0.4.x:
    • export const path = '/v2/users' in a route file overrides the convention-derived path.
    • Tag inference from folder: admin/users.get.ts → tags: [admin].
    • Schema.describe('...') copied to operation.description.
  • hono 0.3.x:
    • Description flow as above.
    • Tag inference from the route path: two-or-more-stem paths get the second-to-last non-param segment.
  • trpc 0.3.x:
    • Description flow on output / input schemas.
    • Subscriptions still emit webhooks: on 3.2 (from v0.2; kept).

New package, zod-contract-auth 0.1.0

This was the v0.4 feature I was most reluctant to ship. Auth is opinionated, and the moment you ship a JWT helper you own the JWT lifecycle: key rotation, issuer validation, clock skew. All on you.

So v0.1.0 deliberately stays at the OpenAPI surface.

import { authPlugin } from '@aemrezorlu/zod-contract-auth'

authPlugin({
  schemes: {
    bearerAuth: { type: 'http', scheme: 'bearer', bearerFormat: 'JWT' },
    apiKeyAuth: { type: 'apiKey', in: 'header', name: 'X-API-Key' },
  },
  require: {
    default: ['bearerAuth'],
    public: ['/health', '/internal/*'],  // wildcard suffix supported
  },
})

Output:

components:
  securitySchemes:
    bearerAuth: { type: http, scheme: bearer, bearerFormat: JWT }
    apiKeyAuth: { type: apiKey, in: header, name: X-API-Key }
paths:
  /health:
    get: {}                                # public, no security
  /users:
    get:
      security: [{ bearerAuth: [] }]

OAuth2, OIDC, mutual TLS are all out of v0.1. Each needs real work on tokenUrl, authorizationUrl, scopes. v0.2.


Lessons from shipping this cycle

Two things I relearned this release:

1. Peer-deps ARE the release contract. Bumping @aemrezorlu/zod-contract ^0.3.0 → ^0.4.0 across three plugins was the most underrated chore of the cycle. Skip it and you leave users on a beta plugin talking to a stable core. They’d run together, sure, but the contract wouldn’t fit. The cost stays invisible until someone hits it on npm install. Then debugging gets ugly.

2. Publish-last beats ship-fast. The order local → commit → publish → report turned chaos into a 50-green-test cycle. I had one premature-release moment this cycle, and the discipline caught it before npm saw it.

If you maintain a plugin family, I’d love to hear how you handle this.


The roadmap through v0.5

After v0.4 ships, three Tier 2 CLI items get attention:

Target Items
v0.4.1 (already shipped, 3 plugins) Peer-dep bumps to ^0.4.0
v0.4.2 (planned) zod-contract watch handles .unlink (removed files don’t leave orphan outputs); ZodContractError class with cause chains + --verbose flag for stack traces
v0.5.0 (planned) zod-contract validate <dir> runs AJV against the generated OpenAPI + JSON examples (CI-friendly). Plus zod-contract-auth v0.2: OAuth2, OpenID Connect, mutual TLS
Parked for v0.6+ Fastify / Express adapters, Drizzle / Prisma → Zod bridge, $ref cycle report, Vitest matchers (toMatchOpenAPISchema(User)), VS Code extension for hover-on-schema

Every entry on this list is something a user has asked for. Prioritization will track what gets adoption traction, not what I find interesting.

If something on the parked list would unblock you, the most useful thing you can do is open an issue with a one-paragraph description of what you’d build on top of it. Adoption signal drives ordering more than “wouldn’t it be cool.”


Try it

npm install --save-dev @aemrezorlu/zod-contract
npx zod-contract init
npx zod-contract build src/schemas api

Add plugins as needed:

npm install @aemrezorlu/zod-contract-paths
npm install @aemrezorlu/zod-contract-hono
npm install @aemrezorlu/zod-contract-auth

50 tests across the five packages, MIT, on npm. Issues and PRs on each repo:

If you ship an API on this, I’d love to hear about it.

— @aemrezorlu

Claude’un AI Watermark’ı Nasıl Çalışıyor?


Token Seçiminden SynthID-Text’e Teknik Bir Bakış

Üretken yapay zekânın yaygınlaşmasıyla birlikte önemli bir soru ortaya çıktı: Bir metnin Claude gibi bir AI sistemi tarafından üretilip üretilmediğini sonradan anlayabilir miyiz?

Anthropic, 14 Ağustos 2026’da Claude’un metin watermark sisteminin nasıl çalıştığını açıkladı. Yaklaşım klasik AI detector sistemlerinden oldukça farklı. Claude çıktısına gizli Unicode karakterleri eklenmiyor, metne ekstra token yerleştirilmiyor ve sistem yalnızca perplexity ölçmüyor.

Bunun yerine watermark, Claude’un metin üretirken yaptığı token seçimlerindeki randomness mekanizmasına yerleştiriliyor. Anthropic, kullandığı yaklaşımın Google DeepMind tarafından geliştirilen SynthID-Text yönteminin bir versiyonu olduğunu açıkça belirtiyor.

Anthropic’in teknik açıklaması

AI Text Watermark Nedir?

Watermark kelimesi genellikle bir görüntünün üzerine eklenen görünür veya görünmez bir işareti ifade ediyor. Ancak Claude’un text watermark sistemi bu şekilde çalışmıyor.

Metne herhangi bir karakter eklenmiyor. Anthropic özellikle “Nothing is added to the text and there are no hidden characters” diyerek bunu açıkça belirtiyor.

Dolayısıyla sistem şu şekilde çalışmıyor:

Normal text:
Hello world
Watermarked text:
Hello world​

Buradaki görünmez karakter bir Unicode watermark örneği olurdu. Claude’un sistemi bunu kullanmıyor.

Watermark, metnin içerisine fiziksel olarak eklenmiş bir veri yerine, metnin nasıl üretildiği içerisinde bulunan istatistiksel bir sinyal.

LLM Bir Sonraki Token’ı Nasıl Seçiyor?

Watermark’ın nasıl çalıştığını anlamak için önce normal bir LLM generation sürecine bakalım.

Prompt
↓
LLM
↓
Next-token probabilities
↓
Sampling
↓
Selected token
↓
Output

Örneğin model şu cümleyi üretiyor olabilir:

The weather today was cold and ...

Model bir sonraki token için bir probability distribution oluşturur:

Token Probability
overcast 32%
grey 25%
rainy 12%
cloudy 10%
sunny 3%
sugary 0.01%

Model burada tek bir doğru cevaba sahip değildir. overcast, grey, rainy veya cloudy gibi seçeneklerin birçoğu cümlenin anlamını bozmaz.

Sampling mekanizması bu olasılık dağılımını kullanarak bir token seçer.

Watermark Tam Bu Noktada Devreye Giriyor

Claude watermark’ının temel fikri oldukça basit: Modelin birden fazla makul token arasından seçim yapabildiği durumlarda, randomness kaynağı watermark ile ilişkilendiriliyor.

Normal generation kabaca şöyle düşünülebilir:

LLM
↓
Token probabilities
↓
Randomness
↓
Token selection
↓
Text

Watermarked generation ise:

LLM
↓
Token probabilities
↓
Watermark key
+
Previous context
↓
Watermark-aware randomness
↓
Token selection
↓
Text

Tek bir token’a baktığımızda bu mekanizmayı anlamak mümkün değil. Ancak binlerce token boyunca yapılan seçimler incelendiğinde istatistiksel bir pattern ortaya çıkabiliyor.

Gizli Unicode Karakterleri Kullanılmıyor

Claude watermark’ını invisible Unicode karakterleri ile karıştırmamak gerekiyor.

Watermark ≠
Zero Width Space
Zero Width Joiner
Zero Width Non-Joiner
Variation Selector
HTML comment
Hidden metadata inside text

Bu yaklaşımın önemli bir avantajı var: Copy/paste sırasında korunması için metnin içerisinde özel karakterlere ihtiyaç duyulmuyor.

Watermark’ın sinyali, karakterlerin kendisinde değil, token seçimlerinin istatistiksel davranışında bulunuyor.

Watermark’ın Gizli Kısmı Nerede?

Buradaki temel bileşenlerden biri watermark key.

Previous context
+
Watermark key
↓
Randomness
↓
Token selection

Detector tarafında ise aynı watermark mekanizması kullanılarak metindeki token seçimlerinin watermark ile ne kadar uyumlu olduğu istatistiksel olarak analiz edilebilir.

Text
↓
Tokenization
↓
Watermark scoring
↓
Statistical analysis
↓
Watermark confidence

Buradaki önemli nokta şu: Detector’ın yalnızca metni görmesi yeterli değil. Watermark’ın oluşturulmasında kullanılan gizli anahtar ve ilgili algoritma bilgileri gerekiyor.

Bu Sistem Perplexity-Based Değil

AI detector ile watermark arasındaki en önemli farklardan biri burada ortaya çıkıyor.

Perplexity, bir modelin belirli bir metin dizisini ne kadar beklenmedik bulduğunu ölçen bir metriktir. Bazı AI detector sistemleri perplexity ve benzeri dilsel istatistiklerden yararlanır.

Classic AI Detector
Text
↓
Perplexity
Style
Sentence patterns
Word choice
↓
AI probability

Claude watermark ise farklı bir problem çözüyor:

Claude Generation
↓
Watermark-aware sampling
↓
Token sequence
↓
Watermark detector
↓
Statistical match

Dolayısıyla perplexity watermark’ın kendisi değil. Watermark, generation sırasında oluşturulan istatistiksel bir sinyale dayanıyor.

Claude ve Google SynthID-Text

Anthropic’in açıklamasındaki en önemli teknik detaylardan biri, Claude text watermark sisteminin Google DeepMind’ın SynthID-Text yaklaşımının bir versiyonu olması.

Google’ın 2024 yılında Nature’da yayımladığı çalışma, LLM çıktılarının token generation sürecinde watermark oluşturulmasını ele alıyor.

LLM
↓
Probability distribution
↓
Watermark mechanism
↓
Sampling
↓
Token
↓
Text

SynthID-Text yaklaşımı için Google, watermarking işlemini modelin sampling aşamasına yerleştiriyor.

Nature: Scalable watermarking for identifying large language model outputs

Tournament Sampling Nedir?

SynthID-Text’in teknik yaklaşımındaki ilginç bileşenlerden biri Tournament Sampling.

Basitleştirilmiş şekilde modelin probability distribution’ından birden fazla aday token seçildiğini düşünelim:

8 candidates
A
B
C
D
E
F
G
H

Daha sonra adaylar bir turnuva mantığıyla karşılaştırılır:

A ─┐
├── Winner ─┐
B ─┘ │
├── Winner
C ─┐ │
├── Winner ─┘
D ─┘
E ─┐
├── Winner ─┐
F ─┘ │
├── Winner
G ─┐ │
├── Winner ─┘
H ─┘

Gerçek algoritma bundan daha karmaşık olsa da temel fikir, modelin doğal probability distribution’ından tamamen kopmadan watermark sinyalini güçlendirecek seçimler yapabilmek.

Model Saçma Kelimeler Seçmeye Başlamıyor

Watermark’ın önemli tasarım hedeflerinden biri de metnin kalitesini bozmamak.

Normal probability:
overcast ██████████
grey ████████
cloudy █████
nubilous ▏

Watermark mekanizması nubilous gibi çok düşük olasılıklı bir kelimeyi sırf watermark oluşturmak için zorla seçmek zorunda değil.

Watermark, modelin zaten makul gördüğü seçenekler arasındaki sampling davranışından yararlanıyor.

Her Token Watermark’lanmıyor

Watermark’ın bir başka önemli özelliği de modelin her seçiminde uygulanmasının mümkün veya mantıklı olmaması.

Örneğin:

2 + 2 = 4

Burada modelin anlamlı bir seçim alanı çok sınırlı. Yanlış bir token seçerek watermark sinyalini güçlendirmek modelin doğruluğunu bozabilir.

Aynı durum bazı factual cevaplar ve deterministik kod parçaları için de geçerli.

if (user == null) {
return;
}

Programlama dillerinde syntax ve semantics doğal dile göre çok daha katı olduğu için watermark’ın kullanılabileceği seçim alanı daralabilir.

Neden Uzun Metinlerde Daha Güçlü?

Watermark istatistiksel bir sinyal olduğu için daha fazla uygun token seçimi, detector’ın daha fazla veri üzerinden değerlendirme yapmasını sağlar.

100 tokens
████
1,000 tokens
████████████████████
5,000 tokens
████████████████████████████████

Bu nedenle uzun yaratıcı metinler, kısa cevaplara göre watermark açısından daha avantajlıdır.

Proofreading Yapılırsa Ne Olur?

Bir insanın yazdığı bir metnin Claude tarafından yalnızca grammar correction amacıyla düzenlendiğini düşünelim.

Human-written article
↓
Claude
"Fix grammar only"
↓
Corrected article

Metnin büyük bölümü insan tarafından üretildiği ve Claude yalnızca küçük değişiklikler yaptığı için watermark sinyali zayıf kalabilir.

Human text:
████████████████████████████████
Claude changes:
██

Translation Neden Daha Güçlü Bir Watermark Oluşturabilir?

Translation senaryosu bunun tersine oldukça farklıdır.

Human-written English
↓
Claude
↓
Turkish translation

Çevirinin büyük bölümündeki token seçimlerini Claude yaptığı için watermark için çok daha fazla fırsat oluşur.

Watermark Sonradan Kırılabilir mi?

Evet. Watermark’ın önemli bir sınırı, metnin daha sonra yeniden yazılması.

Claude
↓
Watermarked text
↓
Light editing
↓
Some watermark signal may remain
Claude
↓
Watermarked text
↓
LLM paraphraser
↓
Complete rewrite
↓
Original token pattern changes

Anthropic, her kelimenin başka bir kelimeyle değiştirilmesi gibi kapsamlı yeniden yazımların watermark’ı ortadan kaldırabileceğini açıkça belirtiyor.

Watermark Kullanıcıyı Tanımlamıyor

Claude watermark’ı bir kullanıcı kimliği veya kişisel bilgi içermiyor.

Watermark
✓ Claude involvement
✗ User identity
✗ User name
✗ Organization identity
✗ Conversation ID

Bu nedenle watermark’ın amacı kullanıcıyı takip etmek değil, içeriğin Claude tarafından üretilmiş veya işlenmiş olabileceğine ilişkin bir provenance sinyali oluşturmak.

Watermark ≠ Authorship Proof

Buradaki en önemli ayrımlardan biri bu.

Bir watermark’ın bulunması şu anlama gelmez:

"This entire article was written by Claude."

Daha doğru yorum şudur:

"Claude was likely involved in generating
or processing this content."

Örneğin insan tarafından yazılmış bir makale Claude ile proofreading işleminden geçirilmişse watermark oluşabilir. Bu durumda metnin temel yazarı insan olabilir.

Claude vs Gemini vs Klasik AI Detector

ÖzellikClaude WatermarkGemini SynthID-TextKlasik AI Detector
Generation sırasında çalışır✅✅❌
Token seçiminden yararlanır✅✅Genellikle dolaylı
Secret key✅✅❌
Unicode karakter ekler❌❌❌
Perplexity temel yöntem❌❌Sıklıkla
Metne ekstra veri ekler❌❌❌
İstatistiksel sinyal✅✅Değişken
Paraphrasing ile zayıflayabilir✅✅✅

Claude ve C2PA Aynı Şey Değil

Anthropic’in yaklaşımında text watermark ile dosya provenance sistemini birbirinden ayırmak gerekiyor.

                    Claude
                       │
             ┌─────────┴─────────┐
             │                   │
            TEXT               FILE
             │                   │
             ▼                   ▼
      Text watermark            C2PA
             │                   │
     Token-selection       Signed metadata
      statistical signal       provenance

Text watermark, metnin generation sürecindeki istatistiksel pattern’e dayanıyor.

C2PA ise desteklenen dosyalarda kriptografik olarak imzalanmış provenance metadata sağlıyor. Anthropic PNG, JPG ve SVG gibi desteklenen dosya türlerinde C2PA content credentials kullanacağını belirtiyor.

Watermarking Claude’u Yavaşlatıyor mu?

Anthropic’in açıklamasına göre watermarking’in model performansına etkisi ihmal edilebilir düzeyde ve ekstra token üretilmediği için ek token maliyeti oluşturmuyor.

Normal generation:
1000 tokens
Watermarked generation:
1000 tokens
Extra watermark tokens:
0

Watermark Nasıl Tespit Edilecek?

Anthropic, watermark detection için bir API sunacağını açıkladı. Ancak detection API’nin teknik ayrıntıları henüz tamamen yayınlanmış değil.

Text
↓
Tokenization
↓
Watermark scoring
↓
Statistical test
↓
Confidence

Bu nedenle bugün için “Claude watermark detector %X doğrulukla çalışıyor” şeklinde kesin bir oran vermek doğru olmaz.

Asıl Değişim: AI Detection’dan AI Provenance’a

Bu teknolojinin bence en önemli tarafı watermark’ın kendisinden çok, AI içerik tespit yaklaşımındaki değişim.

Klasik AI Detection

Text
↓
AI Detector
↓
Perplexity
Style
Sentence patterns
Word choice
↓
"This looks like AI"

AI Watermarking

Claude
↓
Watermark-aware generation
↓
Token sequence
↓
Watermark detector
↓
"Does this match Claude's
generation watermark?"

İlk yaklaşım metnin AI’ya benzeyip benzemediğini tahmin etmeye çalışıyor.

İkinci yaklaşım ise generation sırasında kasıtlı olarak oluşturulmuş bir provenance sinyalini arıyor.

Sonuç

Claude’un text watermark sistemi, klasik AI detector’lardan oldukça farklı bir yaklaşım.

                 CLAUDE
                    │
                    ▼
             Token generation
                    │
                    ▼
          Probability distribution
                    │
                    ▼
       ┌──────────────────────────┐
       │ Watermark mechanism       │
       │                           │
       │ Context                   │
       │ Watermark key             │
       │ Randomness                │
       └────────────┬─────────────┘
                    │
                    ▼
              Token selection
                    │
                    ▼
                  Text
                    │
                    ▼
          ┌───────────────────┐
          │ Watermark         │
          │ Detection         │
          └─────────┬─────────┘
                    │
                    ▼
       Probability Claude involved

Özetle:

  • Token-level: Evet
  • Probability / sampling tabanlı: Evet
  • Unicode: Hayır
  • Hidden characters: Hayır
  • Perplexity: Hayır
  • Extra tokens: Hayır
  • Secret key: Evet
  • SynthID-Text yaklaşımı: Evet
  • C2PA: Metin watermark’ından ayrı olarak dosyalarda kullanılıyor
  • Authorship proof: Hayır
  • AI provenance signal: Evet

En doğru şekilde ifade etmek gerekirse, Claude’un watermark’ı metnin içine bir “işaret” koymuyor. Bunun yerine metnin oluşmasını sağlayan rastgele seçim mekanizmasını değiştirerek, sonradan istatistiksel olarak tanınabilecek bir iz bırakıyor.

Bu yaklaşım, AI içerik tespitinde önemli bir paradigma değişimine işaret ediyor: “Bu metin AI gibi mi yazılmış?” sorusundan, “Bu metin belirli bir AI sisteminin watermark sinyalini taşıyor mu?” sorusuna geçiş.

Teknik Referanslar

Impact of Information Technology Capability on Finance Firms’ Performance


Hi guys I made a research that evaluates the relation of firms’ financial performance and IT capabilities. These are the final results for a medium set.
I hope this will help.

5. CONCLUSION & DISCUSSION

In this study, IT capabilities of the financial firms are studied as one of the core competencies that is accepted as one of the important capability in the framework of the resource-based view. Its basics definition and characteristics of the core competency are explained as well as its practical usage and benefits in the theoretical framework. After that technical IT capability, managerial IT capability and Human capital support are examined as a sub-dimension of IT capability. Their effects on the financial performance of the financial companies are studied afterward. Therefore, three main hypothesizes put forward, but findings suggest that technical IT capability and managerial IT capability must be approached together. For this reason, main hypothesizes form into integrated (technical and managerial) IT capability and Human Capital Support has a meaningful and positive effect on firms’ financial performance. This study is also of importance based on the fact that the financial performance indicators are taken from Association of Banks of Turkey (ABT).
Continue to read