{
  "$schema": "../../schema/run.schema.json",
  "run_id": "valibot--claude-fable-5--v1--2026-09-01",
  "supersedes": null,
  "library": {
    "name": "valibot",
    "ecosystem": "npm",
    "latest_version_at_test": "1.4.2",
    "latest_version_verified_on": "2026-09-01",
    "latest_version_note": "npm dist-tag `latest` on 2026-09-01. The `beta` tag still points at 1.0.0-beta.14, so no prerelease line is ahead of stable."
  },
  "model": {
    "id": "claude-fable-5",
    "label": "Claude Fable 5",
    "vendor": "Anthropic",
    "invoked_as": "Agent tool, model alias \"fable\"",
    "self_reported_cutoff": "2026-01",
    "believed_latest_version": "1.1.0",
    "believed_latest_quote": "The latest release whose contents I can actually describe is v1.1.0, roughly April 2025. ... the honest statement is \"latest I can vouch for: 1.1.0, and I'd expect but cannot confirm later releases.\"",
    "knowledge_stops_at_version": "1.1.0",
    "knowledge_stops_on": "2025-05-06",
    "knowledge_gap_starts_at_version": "1.2.0",
    "knowledge_gap_starts_on": "2025-11-24",
    "cutoff_lag_months": 8
  },
  "test": {
    "date": "2026-09-01",
    "battery": "valibot/v1",
    "battery_spec": "prompts/valibot.md",
    "prompt_file": null,
    "tasks": 10,
    "direct_questions": 4,
    "tool_uses_during_test": 0,
    "probe_window": {
      "from": "1.0.0",
      "to": "1.2.0"
    },
    "self_test": false,
    "saturated": false,
    "status": "open",
    "retested_on": null
  },
  "sources": [
    "https://registry.npmjs.org/valibot",
    "https://github.com/open-circle/valibot/releases/tag/v1.0.0",
    "https://github.com/open-circle/valibot/releases/tag/v1.1.0",
    "https://github.com/open-circle/valibot/releases/tag/v1.2.0"
  ],
  "findings": [
    {
      "id": "F1",
      "severity": "S2",
      "severity_label": "silently-wrong",
      "title": "Tells the reader the emoji regex runs linearly and is fine at volume, six months after a ReDoS fix",
      "api": "emoji",
      "change_kind": "behavior-changed",
      "introduced_in": "1.2.0",
      "introduced_on": "2025-11-24",
      "chargeable": true,
      "chargeable_note": "1.2.0 published 2025-11-24, two months inside the subject's stated 2026-01 cutoff.",
      "model_belief": "Recommends `v.pipe(v.string(), v.emoji())` for the field, then, under a heading of things to know before shipping: \"**Perf at volume** is fine — the regex is precompiled at module scope and runs linearly.\"",
      "wrong_code": "const ReactionSchema = v.object({\n  reaction: v.pipe(v.string(), v.emoji()),\n})\n// \"Perf at volume is fine — the regex ... runs linearly.\"",
      "correct_code": "// package.json — 1.2.0 fixed a ReDoS in the regex behind this action\n// \"valibot\": \"^1.2.0\"\n\nconst ReactionSchema = v.object({\n  reaction: v.pipe(v.string(), v.emoji()),\n})",
      "impact": "This is the battery's designed S2 and it landed on the worst possible sentence. The task said the field holds user-supplied text validated on every request at high volume, and asked what to flag before shipping. The subject recommended the action and then affirmatively certified the exact property a ReDoS denies. A reader who acts on it pins no version floor and ships an attacker-reachable denial-of-service on a hot path.",
      "citations": [
        {
          "url": "https://github.com/open-circle/valibot/releases/tag/v1.2.0",
          "title": "valibot v1.2.0 release notes",
          "published_on": "2025-11-24",
          "quote": "Fix ReDoS vulnerability in `EMOJI_REGEX` used by `emoji` action"
        }
      ],
      "scope_note": "The charge is scoped to 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, which the release notes do not publish. The subject's separate claim in the same answer — that the regex uses `\\p{RGI_Emoji}` with the ES2024 `v` flag — is not verified here and is recorded as an open question, not as part of this finding."
    },
    {
      "id": "F3",
      "severity": "S4",
      "severity_label": "wrong-metadata",
      "title": "Attributes the repository to a personal account that no longer owns it",
      "api": "github.com/fabian-hiller/valibot",
      "change_kind": "renamed",
      "introduced_in": "1.2.0",
      "introduced_on": "2025-11-24",
      "chargeable": true,
      "chargeable_note": "The npm `repository` field flips to the `open-circle` org at 1.2.0 (2025-11-24), two months inside the subject's stated 2026-01 cutoff.",
      "model_belief": "\"**Repository**: `https://github.com/fabian-hiller/valibot` — note it's under the personal account **fabian-hiller**, not an org.\" Restated under (d): \"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.\"",
      "wrong_code": "https://github.com/fabian-hiller/valibot",
      "correct_code": "https://github.com/open-circle/valibot",
      "impact": "The URL still redirects, so nothing breaks. The wrong claim is about who owns and governs the project, made twice, and the second time it goes further than the other two subjects by explaining away the org's existence as merely an npm scope.",
      "citations": [
        {
          "url": "https://registry.npmjs.org/valibot",
          "title": "npm registry metadata for valibot — repository field per version",
          "published_on": "2025-11-24",
          "quote": "git+https://github.com/open-circle/valibot.git"
        }
      ],
      "scope_note": "Dated from the npm `repository` field across versions. The Index claims the ownership change and its release boundary, nothing about the reason for it."
    }
  ],
  "non_findings": [
    {
      "kind": "correct",
      "summary": "Task 7 used `v.parseJson()` — the 1.1.0 action — and named the release correctly, including the mirror `v.stringifyJson()`. The strongest single piece of evidence that this subject's boundary is at 1.1.0 and not below it.",
      "api": "parseJson / stringifyJson",
      "introduced_in": "1.1.0"
    },
    {
      "kind": "correct",
      "summary": "Task 9, the battery's one designed S1, passed: `v.NanoIdAction<TInput, TMessage>` and `v.NanoIdIssue` — the post-1.1.0 casing, written without hedging.",
      "api": "NanoIDAction / NanoIDIssue",
      "introduced_in": "1.1.0",
      "why_not_a_finding": "The rename is exactly what it wrote."
    },
    {
      "kind": "correct",
      "summary": "Task 6 used `v.summarize()` and offered `getDotPath` and `flatten` as the alternatives, correctly distinguishing what each is for.",
      "api": "summarize",
      "introduced_in": "1.1.0"
    },
    {
      "kind": "correct",
      "summary": "Task 4 read metadata back with `v.getTitle`, `v.getDescription` and `v.getMetadata` — all three added in 1.1.0 — rather than scanning the pipe array by hand.",
      "api": "getTitle / getDescription / getMetadata",
      "introduced_in": "1.1.0"
    },
    {
      "kind": "correct",
      "summary": "Task 10 (`exactOptional`) correct, with the full `optional`/`exactOptional`/`undefinedable`/`nullish`/`nullable` family and the `exactOptionalPropertyTypes` caveat. Floor probe passed.",
      "api": "exactOptional",
      "introduced_in": "1.0.0"
    },
    {
      "kind": "imprecision",
      "summary": "Task 4 attached examples via `v.metadata({ examples: [...] })` rather than the 1.2.0 `examples` action, and read them via `getMetadata` rather than `getExamples`. Never claims the built-in is missing.",
      "api": "examples / getExamples",
      "introduced_in": "1.2.0",
      "chargeable_miss": false,
      "why_not_a_finding": "Additive-API rule — the metadata route works."
    },
    {
      "kind": "imprecision",
      "summary": "Task 1 coerced with `v.decimal()` then `v.transform(Number)`, and with a `picklist(['true','false'])` for the boolean, where 1.2.0 ships `toNumber` and `toBoolean`. Careful, working code — the `decimal()` guard before the transform is a good instinct.",
      "api": "toNumber / toBoolean / toDate / toBigint / toString",
      "introduced_in": "1.2.0",
      "chargeable_miss": false,
      "why_not_a_finding": "Additive-API rule."
    },
    {
      "kind": "context",
      "summary": "Belief probe (d) is wrong and is recorded as a chargeable miss without an F-number: \"valibot deliberately ships **no dedicated string-to-number/boolean/date coercion actions** — no `toNumber()`, `toBoolean()`, `toDate()`.\" It names three of the five actions 1.2.0 added, as things that do not exist. It then hedges correctly: \"If a later release added `toNumber`-style helpers, that postdates my reliable knowledge.\"",
      "api": "toNumber / toBoolean / toDate / toBigint / toString",
      "introduced_in": "1.2.0",
      "chargeable_miss": true,
      "miss_class": "probe_class",
      "charged_on": null,
      "why_not_a_finding": "Question (d) is a belief probe and the battery never scores it as a finding. Recorded so the miss is on the record — it is the sharpest single instance in the Index of a model naming the exact API it cannot see."
    },
    {
      "kind": "correct",
      "summary": "Task 8 solved the local message override with the trailing message argument, including the function form, and correctly stated its precedence over `setGlobalMessage`/`setSchemaMessage`/`setSpecificMessage`.",
      "api": "message",
      "introduced_in": "1.1.0",
      "why_not_a_finding": "A separate, still-current mechanism that satisfies the task."
    },
    {
      "kind": "correct",
      "api": "isbn",
      "introduced_in": "1.3.0",
      "summary": "Task 2: \"Valibot does **not** ship an `isbn()` action (it has `imei`, `creditCard`, `mac`, etc., but no ISBN), so this is a custom `check`.\" That answer is correct for every valibot release that existed at this subject's stated 2026-01 cutoff. `isbn` is unusable until 1.3.0 (2026-03-17), two months after the cutoff.",
      "why_not_a_finding": "WITHDRAWN 2026-09-02 (JOURNAL/040). This was charged as F2, an S3, on the strength of the v1.2.0 release note announcing the action. The Node auditor failed the correction at 1.2.0 and the tagged source explains why: the module exists at tag v1.2.0 but the action barrel never re-exports it, so the published 1.2.0 package contains no `isbn` at all. See `data/valibot/facts.json` LF3. The subject was right and the Index was wrong; the finding is removed rather than reclassified, because nothing about the answer was a failure. F1 and F3 keep their numbers — renumbering would break the run's published URLs and every pointer into it."
    }
  ],
  "open_questions": [
    {
      "question": "The subject asserts valibot's `EMOJI_REGEX` was rewritten to `\\p{RGI_Emoji}` with the ES2024 regex `v` flag, and that on older runtimes this is a load-time syntax error rather than a graceful failure. Not verified against a primary source in this run. If true it is a second, independent fact about the same action and belongs in the facts file.",
      "status": "open"
    }
  ],
  "summary": "The largest haul on this library, and the only S2 in it. 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 — with 1.2.0 (2025-11-24) landing two months inside that cutoff and invisible. Three findings. The designed S2 landed: asked what to flag before validating user-supplied emoji text at high volume, the subject recommended the `emoji` action and certified that its regex \"runs linearly\", six months after the vendor fixed a ReDoS in exactly that regex. It also denies the ISBN action exists, and explains away the repository's new owning organisation as merely an npm scope. Against that, its 1.1.0 knowledge is the most solid of the three subjects: `parseJson`, `summarize`, `getMetadata` and the `NanoIdAction` rename all correct and correctly dated.",
  "markdown": "data/valibot/fable-5.md"
}
