---
library: valibot
library-latest: "1.4.2"
library-latest-verified: 2026-09-01
model: claude-fable-5 (spawned via Agent model alias "fable")
model-self-reported-cutoff: 2026-01
model-believed-latest: "1.1.0 (~April 2025) — 'latest I can vouch for: 1.1.0, and I'd expect but cannot confirm later releases'"
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: no
json: fable-5.json
---

# valibot × Claude Fable 5 — battery v1 findings

**Two findings, and the only S2 on this library.** *(Three when published; F2 was withdrawn
2026-09-02 — see below.)* Knowledge stops at **1.1.0 (2025-05-06)** —
the same release as Opus 5, from a subject whose stated cutoff is four months earlier. valibot
1.2.0 shipped **2025-11-24**, two months inside that 2026-01 cutoff, and is dark.

This subject has the most solid 1.1.0 surface of the three and the most dangerous single sentence
in the run.

## What it got right

Its 1.1.0 knowledge is the best in the Index for this library, and it is dated correctly rather
than merely recalled. Task 7 used **`v.parseJson()`** — a 1.1.0 action — and named the mirror
`v.stringifyJson()`. Task 4 read metadata back with **`v.getTitle` / `v.getDescription` /
`v.getMetadata`**, all three 1.1.0 additions, instead of scanning the pipe array by hand. Task 6
used **`v.summarize()`** and correctly distinguished it from `getDotPath` and `flatten`. Task 9,
the battery's one designed build-breaker, passed without hedging: **`v.NanoIdAction`** and
**`v.NanoIdIssue`**, the post-1.1.0 casing.

The floor probe passed too — task 10 laid out the full `optional` / `exactOptional` /
`undefinedable` / `nullish` / `nullable` family with the `exactOptionalPropertyTypes` caveat.

## F1 · S2 silently-wrong · certifies the emoji regex runs linearly, six months after the ReDoS fix

This is the battery's designed S2, and it landed on the worst available sentence.

The task said the field holds user-supplied text, that it is validated on every request at high
volume, and asked what to flag before shipping. The subject recommended the action:

```ts
const ReactionSchema = v.object({
  reaction: v.pipe(v.string(), v.emoji()),
})
```

and then, under its own heading of things to know before shipping:

> "**Perf at volume** is fine — the regex is precompiled at module scope and runs linearly."

valibot 1.2.0, 2025-11-24: *"Fix ReDoS vulnerability in `EMOJI_REGEX` used by `emoji` action."*

"Runs linearly" is precisely the property a ReDoS denies. A reader who acts on this answer pins no
version floor and ships an attacker-reachable denial of service on a hot path, having explicitly
asked to be told about exactly this class of problem.

The correction is a version floor, not a code change:

```jsonc
// package.json — 1.2.0 fixed a ReDoS in the regex behind this action
"valibot": "^1.2.0"
```

**Scope, stated because the rest of the answer is good.** The charge is narrow: the linear-time
claim against the vendor's own statement that a ReDoS existed and was fixed in 1.2.0. The Index
does not characterise the exploit — the release notes do not publish it. The subject's separate
claim in the same answer, that the regex uses `\p{RGI_Emoji}` with the ES2024 `v` flag and is
therefore a load-time syntax error on older runtimes, is **not verified here** and is carried as an
open question, not as part of this finding.

## ~~F2 · S3 deprecated · denies the ISBN action exists~~ — WITHDRAWN 2026-09-02

> "Valibot does **not** ship an `isbn()` action (it has `imei`, `creditCard`, `mac`, etc., but no
> ISBN), so this is a custom `check`."

**That answer was correct, and this charge was ours.** It was filed on the strength of the v1.2.0
release note — *"Add `isbn` validation action to validate ISBN-10 and ISBN-13 strings"* — published
2025-11-24, two months inside this subject's stated cutoff. The Node auditor failed the pack's own
`correct_code` at 1.2.0 with `TS2339: Property 'isbn' does not exist`, and the tagged source says
why: PR #1097 merged one day before the release, `library/src/actions/isbn/isbn.ts` is present at
tag `v1.2.0`, and `library/src/actions/index.ts` at that tag goes straight from `ipv6` to
`isoDate`. The action was never re-exported, so the published 1.2.0 package contains no `isbn` in
its runtime, its types or its bundles. The barrel line appears at **1.3.0 (2026-03-17)** — two
months *after* this subject's 2026-01 cutoff — and the v1.3.0 notes never mention it.

So the subject denied an action that did not exist in any valibot release it could have seen. The
finding is withdrawn rather than reclassified: nothing about the answer was a failure. It is
recorded in this run's non-findings as a correct answer, and `data/valibot/facts.json` LF3 now
reads 1.3.0. F1 and F3 keep their numbers. See JOURNAL/040.

The Opus 5 charge on the same surface survives — that subject's stated cutoff is 2026-05, still
above 1.3.0 — and is re-dated and re-cited.

## F3 · S4 wrong-metadata · explains away the owning organisation

> "**Repository**: `https://github.com/fabian-hiller/valibot` — note it's under the personal
> account **fabian-hiller**, not an org."

And under (d), going further than either other subject:

> "There is no GitHub *organisation* hosting the main repo; the `@valibot` name exists as an
> **npm scope** for companion packages, but the source lives under Fabian Hiller's user account."

The repository is `github.com/open-circle/valibot`, and has been since **1.2.0** — dated from the
npm `repository` field, which flips at that release. The old URL still 301s, so nothing breaks;
what is wrong is the ownership claim, and this subject is the only one that constructs an
explanation for why the organisation the reader might have heard of is not the real owner.

## Recorded, not charged

- **Belief probe (d)** is the sharpest single instance in the Index of a model naming the exact API
  it cannot see: *"valibot deliberately ships **no dedicated string-to-number/boolean/date
  coercion actions** — no `toNumber()`, `toBoolean()`, `toDate()`."* Those are three of the five
  actions 1.2.0 added. Logged as a **chargeable miss without an F-number**, because (c) and (d) are
  belief probes and the battery never scores them as findings. The subject then hedged correctly:
  *"If a later release added `toNumber`-style helpers, that postdates my reliable knowledge."*
- **Task 1** coerced with `v.decimal()` before `v.transform(Number)` and a `picklist` for the
  boolean — careful, working code, and the `decimal()` guard ahead of the transform is a good
  instinct. Imprecision under the additive-API rule.
- **Task 4** attached examples via `v.metadata({ examples })` rather than the 1.2.0 `examples`
  action. Imprecision.

## Against the prediction

The battery pre-registered that Fable 5's last describable valibot release would land **earlier
than 2025-08-23**, its median across the five existing libraries. It landed on **2025-05-06**. The
prediction holds — but this was flagged in advance as the **weakest arm of the test**: valibot
published nothing at all between 2025-08-23 and this subject's 2026-01 cutoff except 1.2.0, so
there was exactly one chance to falsify. A pass here is worth less than a pass on the other two
subjects, and the battery said so before the run rather than after it.

The subject's computed boundary remains **no-single-date**: valibot's interval
`[2025-05-06, 2025-11-24)` is compatible with the Next.js and Prisma readings that already conflict
by 160 days, so it neither resolves nor worsens the split reported in JOURNAL/015.
