---
library: valibot
library-latest: "1.4.2"
library-latest-verified: 2026-09-01
model: claude-opus-5 (spawned via Agent model alias "opus")
model-self-reported-cutoff: 2026-05
model-believed-latest: "1.1.x line; 1.1.0 (~mid-2025) is the last release whose contents it can describe, and it holds that loosely"
test-date: 2026-09-01
battery: valibot/v1 (10 idiomatic tasks + 4 direct questions; probes 1.0.0–1.2.0 for this subject)
tool-uses-during-test: 0
verified-against: https://registry.npmjs.org/valibot · https://github.com/open-circle/valibot/releases/tag/v1.2.0 · https://github.com/open-circle/valibot/releases/tag/v1.1.0
status: open (no retest yet)
self-test: yes — the operator model is the subject
json: opus-5.json
---

# valibot × Claude Opus 5 — battery v1 findings

**Ten tasks, ten pieces of working valibot, and a twelve-month lag.** The subject with the deepest
stated cutoff in the Index — 2026-05 — stops at **1.1.0, published 2025-05-06**. valibot 1.2.0
shipped **2025-11-24**, six months inside that cutoff, and is invisible.

Neither finding is broken code. Both are the model asserting something about the world that
stopped being true with the release it cannot see.

## What it got right

The floor probe passed, which is what makes the boundary reading above a measurement rather than
an artefact. Task 10 drew a complete and correct account of `exactOptional` against `optional`,
`undefinedable` and `nullish`, including the detail that the runtime distinction holds
unconditionally while the *type-level* half needs `exactOptionalPropertyTypes` in `tsconfig.json`.

The battery's one designed build-breaker also passed. Task 9 asked for a helper whose signature
names the nano-ID action's type — the interface 1.1.0 renamed from `NanoIDAction` to
`NanoIdAction`. The subject wrote the post-rename casing, and volunteered that this identifier was
the one part of the answer worth checking against the installed `.d.ts`. It also used
`v.summarize()` on task 6 rather than hand-rolling the CLI printer, though it dated the API to
"around v1.0" when it is 1.1.0.

Task 3 is the one worth reading in full. Asked about validating emoji-bearing text at high volume,
it argued the reader out of the `emoji` action entirely — `emoji()` asserts a string *is* emoji,
not that it *contains* emoji — and then gave a genuinely good performance answer about
`Intl.Segmenter` cost and gating `maxGraphemes` behind a cheap `maxLength`.

## F1 · S3 deprecated · denies the ISBN action exists

> "There is **no `v.isbn()` action** in valibot (the string action set covers `email`, `uuid`,
> `ulid`, `cuid2`, `nanoid`, `ip`, `imei`, `creditCard`, `bic`, `mac`, `hexColor`, `isoDate`… but
> not ISBN)."

**RE-DATED 2026-09-02 (JOURNAL/040): the action is usable from 1.3.0, not 1.2.0.** The v1.2.0
release notes do say *"Add `isbn` validation action to validate ISBN-10 and ISBN-13 strings"* — and
the published 1.2.0 package contains no `isbn` at all. PR #1097 merged the day before the tag and
`library/src/actions/isbn/isbn.ts` is present at tag `v1.2.0`, but the action barrel at that tag
goes straight from `ipv6` to `isoDate`, so it was never re-exported. The line
`export * from './isbn/index.ts';` first appears at **v1.3.0, 2026-03-17**, whose own notes never
mention it. **This charge survives**: 1.3.0 is still two months inside this subject's stated 2026-05
cutoff. The same correction withdrew the Fable 5 charge on this surface, whose 2026-01 cutoff falls
below 1.3.0.

The code that follows the denial is correct — a proper ISBN-10 mod-11 and ISBN-13 alternating-
weight checksum, normalised for hyphens, with a `v.brand()` on top. It is also about thirty lines
the reader does not need:

```ts
const Isbn = v.pipe(v.string(), v.isbn())
```

This is charged under the battery's **additive-API rule**: where a release adds something, solving
the task without it is an imprecision, and it becomes a finding only when the model states the
capability does not exist. It does, in bold, alongside an action list presented as exhaustive.

## F2 · S4 wrong-metadata · the repository moved and the model insists it did not

> "**Repository:** `https://github.com/fabian-hiller/valibot` — note this is a **personal GitHub
> account, not an organisation**. There is no `valibot` org holding the source."

And again, unprompted, under direct question (d): *"The GitHub **organisation is: none**."*

valibot's repository is `github.com/open-circle/valibot`. The move is dated from primary metadata
rather than from an announcement: the npm `repository` field reads `fabian-hiller/valibot` for
1.0.0 and 1.1.0 and `open-circle/valibot` from **1.2.0** onward. (This used to read "the same
release that carries the ISBN action above"; it no longer does — see the re-dating in F1.)

Nothing breaks. GitHub 301-redirects the old path, and the subject even reasons its way to that:
*"If it ever moved to a dedicated org after my knowledge horizon, GitHub would redirect the old
path, so that URL remains the right thing to type either way."* That is correct about the link and
wrong about the project. What the reader is told — twice, emphatically — is that valibot is one
person's personal repository, when it has been organisation-owned since the release under test.
Hence S4: wrong metadata, working link.

## Recorded, not charged

- **The coercion claim**, from belief probe (d): *"**Coercion helpers: valibot ships none.** There
  is no `v.coerce.number()`, no `v.coerce.boolean()`, no `v.coerce.date()` — no `coerce` namespace
  at all. This is a deliberate design decision."* 1.2.0 shipped `toBigint`, `toBoolean`, `toDate`,
  `toNumber` and `toString`. The narrow claim survives — there is still no `v.coerce.*` namespace,
  and the 1.2.0 additions are pipe actions — but "ships none" and the design rationale do not.
  Questions (c) and (d) are leading by construction and the battery scores them as belief data, so
  this is logged as a **chargeable miss without an F-number** rather than inflating the count.
- **Task 1** hand-rolled the coercion the same way, and is an imprecision only: the in-task
  sentence claims no `coerce` *namespace*, which is true, and the code is careful — it re-asserts
  `v.number()` to catch `NaN`, and uses a `picklist` for the boolean rather than walking into
  `Boolean("false") === true`.
- **Task 3 drew no charge.** The designed S2 was the ReDoS in `EMOJI_REGEX` that 1.2.0 fixed, and
  the subject never mentions it despite being asked point-blank to flag anything worth knowing.
  But it also never recommends the vulnerable action — it spends the answer arguing against it. A
  security fact the model omits is only a finding when its advice would walk the reader into the
  hazard. Scored strictly against ourselves.
- **Task 4** routed examples through `v.metadata({ examples })` plus a bespoke twenty-line pipe
  scanner, where 1.2.0 ships the `examples` action and `getExamples`. Additive-API rule:
  imprecision.
- **Task 7** built the JSON pipeline from `rawTransform` by hand rather than `v.parseJson()`
  (1.1.0) — the one place its 1.1.0 knowledge is thinner than its self-report.

## The subject stating the Index's own thesis

Unprompted, under (b):

> "a cutoff date is not a uniform knowledge horizon: coverage of a mid-sized npm library thins out
> well before the nominal date, and for valibot specifically my detailed recall degrades sharply
> after early-to-mid 2025. So the effective horizon for *this* question is roughly a year earlier
> than the nominal cutoff."

Measured lag, from the ruler rather than from the introspection: **twelve months**. The subject's
estimate of its own staleness was, on this library, exactly right.

## Against the prediction

The battery pre-registered, before this run: Opus 5's last describable valibot release will land
**earlier than 2025-10-17**, its median across the five existing libraries. It landed on
**2025-05-06**. The prediction holds, and it held with two chances to fail — 1.2.0 and 1.3.0 were
both inside this subject's cutoff and it described neither.

Adding valibot's interval `[2025-05-06, 2025-11-24)` to the other five leaves this subject's
computed knowledge boundary **unchanged at 2025-11-19 → 2025-11-24, five days**, now agreed by six
libraries instead of five.
