{
  "$schema": "../../schema/run.schema.json",
  "run_id": "langchain--claude-fable-5-1--v5-a--2026-09-06",
  "supersedes": null,
  "replicate_of": null,
  "library": {
    "name": "langchain",
    "ecosystem": "pypi",
    "latest_version_at_test": "1.4.0",
    "latest_version_verified_on": "2026-09-06",
    "latest_version_note": "Re-fetched this session from PyPI. 1.4.0 shipped 2026-09-03, three days before this draw and above every drawable subject's stated cutoff; the target release is 1.3.0 (2026-05-12) and the release below the window is 1.2.18 (2026-05-08). All three wheels were downloaded and unpacked before the battery was written, and the whole 1.2.18 -> 1.3.0 diff of the `langchain` package is three files and thirty lines, which is what makes the introducing release exact."
  },
  "model": {
    "id": "claude-fable-5-1",
    "label": "Claude Fable 5.1",
    "vendor": "Anthropic",
    "invoked_as": "Agent tool, model alias \"fable\"; prompt sent verbatim from prompts/sent/langchain-v5.txt, no tools used by the subject. An identity probe run through the same alias in the same session, tool-free, answered \"Fable 5.1\", model id `claude-fable-5-1`, cutoff June 2026, and again volunteered that all three come from its system prompt rather than from self-knowledge - unchanged from every prior battery, so the alias has not moved (JOURNAL/054).",
    "self_reported_cutoff": "2026-06",
    "cutoff_basis": "\"My training cutoff is June 2026, but my reliable, detailed knowledge of this library's release contents is noticeably thinner after about the end of 2025.\" A density qualification, not a substitute cutoff (JOURNAL/055), so the licence holds. June 2026 is after langchain 1.3.0 (2026-05-12) and is not the same month, so the same-month bar of JOURNAL/060 does not apply and this arm may charge.",
    "believed_latest_version": "1.2.x, held as a number",
    "believed_latest_quote": "\"The latest version I know of by name is roughly langchain 1.2.x (the 1.x line, late 2025 / very early 2026). The most recent release whose contents I can genuinely describe is langchain 1.1 (around November 2025); I have only vague awareness of 1.2.\"",
    "knowledge_stops_at_version": "1.1.0",
    "knowledge_stops_on": "2025-11-24",
    "knowledge_gap_starts_at_version": "1.2.0",
    "knowledge_gap_starts_on": "2025-12-15",
    "cutoff_lag_months": 6
  },
  "test": {
    "date": "2026-09-06",
    "battery": "langchain/v5-a",
    "battery_spec": "prompts/langchain.md",
    "prompt_file": "prompts/sent/langchain-v5.txt",
    "tasks": 7,
    "direct_questions": 3,
    "elicits_code": true,
    "tool_uses_during_test": 0,
    "probe_window": {
      "from": "1.2.0",
      "to": "1.4.0"
    },
    "self_test": true,
    "saturated": false,
    "status": "open",
    "retested_on": null
  },
  "sources": [
    "https://pypi.org/pypi/langchain/json",
    "https://docs.langchain.com/oss/python/releases/changelog",
    "https://files.pythonhosted.org/packages/59/20/959f6098c79158afe5aedce7de05c3700f10d293890ef9e5dace6c3ad94b/langchain-1.2.18-py3-none-any.whl",
    "https://files.pythonhosted.org/packages/7b/6f/b9a9721c27fbb6d29a6a7cd89d6a41eeffc7c79b49b9a5cf5beb1d60952d/langchain-1.3.0-py3-none-any.whl",
    "https://files.pythonhosted.org/packages/92/fa/7da07d9977a5e292ef602c1bb911514ff8206e85dc09a66961874345d57a/langchain-1.4.0-py3-none-any.whl"
  ],
  "findings": [
    {
      "id": "F1",
      "severity": "S3",
      "severity_label": "deprecated",
      "title": "Denies that `create_agent` can register stream transformers at all, then ships a consumer-side wrapper that rebuilds per-scope identity by hand - the verdict and the artefact wrong in the same direction, four tasks apart",
      "api": "create_agent(transformers=...)",
      "change_kind": "added",
      "introduced_in": "1.3.0",
      "introduced_on": "2026-05-12",
      "chargeable": true,
      "chargeable_note": "1.3.0 shipped 2026-05-12; this draw states a June 2026 cutoff, which is after it and not the same month, so the fairness rule and the same-month bar both clear. This is the pre-registered charging arm and tasks 1 and 5 are pre-registered probes on this surface. **One finding, two artefacts** (JOURNAL/062): the pre-registration graded the verdict (task 1) and the artefact (task 5) independently and this draw got both wrong in the same direction, which is one belief measured twice.",
      "model_belief": "Task 1, single word on its own line: \"No\", glossed \"I am not aware of a public 'stream transformer' / scope-aware factory API on the compiled graph at all; if one exists it is newer than what I can describe with confidence.\" Task 5, four tasks later: \"The library, as I know it, gives me no way to register a transformer on the compiled graph, so here is what I would actually ship\" - a `TransformingAgent` wrapper that calls `.astream(..., subgraphs=True)` and keys a `dict` of transformer instances off the namespace tuple to reconstruct the per-scope property the parameter already provides. Task 7, on which release added it: \"I cannot name one. In every release I can describe ... there is no way to register your own stream transformers on the compiled agent.\" The subject also listed the parameters it believes `create_agent` takes - model, tools, system_prompt, middleware, response_format, state_schema, context_schema, checkpointer, store, interrupt_before/after, debug, name, cache - which is exactly the 1.2.18 signature with `transformers` missing.",
      "wrong_code": "# The artefact from task 5: the capability is denied, so per-scope identity is\n# reconstructed on the consumer side from subgraph namespace tuples.\nclass TransformingAgent:\n    async def astream(self, inputs, *, stream_mode=\"updates\", config=None):\n        per_scope: dict[tuple, MyTransformer] = {}\n        async for ns, mode, chunk in self._graph.astream(\n            inputs, config=config, stream_mode=[stream_mode], subgraphs=True\n        ):\n            if ns not in per_scope:\n                per_scope[ns] = self._factory(ns)   # invoked once per scope\n            yield per_scope[ns](mode, chunk)",
      "correct_code": "# 1.3.0 and later: the factory is registered on the graph the agent compiles,\n# after the built-in ToolCallTransformer, and is invoked once per scope.\nagent = create_agent(\n    model,\n    tools,\n    system_prompt=\"...\",\n    transformers=[MyTransformer],\n)",
      "impact": "The wrapper runs, which is why this is S3 rather than S1: a reader who follows it ships working code and never learns the parameter exists. What it costs is the wrapper itself, and the guarantee that comes with the supported path - the agent registers `ToolCallTransformer` first and appends yours after it, so the built-in behaviour is kept rather than reimplemented.",
      "citations": [
        {
          "url": "https://files.pythonhosted.org/packages/7b/6f/b9a9721c27fbb6d29a6a7cd89d6a41eeffc7c79b49b9a5cf5beb1d60952d/langchain-1.3.0-py3-none-any.whl",
          "title": "langchain 1.3.0 published wheel - langchain/agents/factory.py",
          "published_on": "2026-05-12",
          "quote": "transformers: Optional sequence of scope-aware `StreamTransformer` factories to register on the compiled graph in addition to the agent defaults. Each factory is invoked per-scope (`factory(scope)`) so subgraph mini-muxes get fresh instances. Appended after the built-in `ToolCallTransformer`."
        },
        {
          "url": "https://files.pythonhosted.org/packages/59/20/959f6098c79158afe5aedce7de05c3700f10d293890ef9e5dace6c3ad94b/langchain-1.2.18-py3-none-any.whl",
          "title": "langchain 1.2.18 published wheel - the release below the window, with no such parameter",
          "published_on": "2026-05-08"
        },
        {
          "url": "https://docs.langchain.com/oss/python/releases/changelog",
          "title": "LangChain changelog - langchain v1.3.0, May 12, 2026",
          "published_on": "2026-05-12",
          "quote": "This release adds support for version=\"v3\" in stream_events / astream_events for langchain agents."
        }
      ]
    },
    {
      "id": "F2",
      "severity": "S3",
      "severity_label": "deprecated",
      "title": "Names `v2` as the highest event-stream protocol version an agent accepts, and describes it as the ceiling - v3 shipped for langchain agents in the same release as F1's parameter",
      "api": "astream_events(version=\"v3\") on a create_agent agent",
      "change_kind": "added",
      "introduced_in": "1.3.0",
      "introduced_on": "2026-05-12",
      "chargeable": true,
      "chargeable_note": "Same window and same licence as F1. Charged separately from F1 because it corrects a different published fact (LF38, not LF37) on a different API surface; JOURNAL/062's one-finding rule is about one belief measured by two tasks, not about two surfaces that happen to ship in one release.",
      "model_belief": "Task 6(a), the string on its own line: \"v2\". Task 6(b): \"`v2` gives a consistent, normalised event schema: `parent_ids` on every event, `on_chat_model_end`/`on_tool_end` outputs as the actual message/tool result rather than wrapped `LLMResult`-style objects, and consistent naming/ordering of nested events - `v1` had known inconsistencies that `v2` was introduced to fix, and it is the version the docs and the `create_agent` graph are exercised against.\" Every word of that is a correct description of the v1 -> v2 change; what is wrong is that it is offered as the top of the ladder.",
      "wrong_code": "async for event in agent.astream_events(inputs, version=\"v2\"):\n    ...",
      "correct_code": "async for event in agent.astream_events(inputs, version=\"v3\"):\n    ...  # run.values / run.messages / run.lifecycle / run.subgraphs",
      "impact": "v1 and v2 are unchanged at 1.3.0, so the code the belief produces still runs; the cost is that the consumer hand-builds typed per-channel projections the protocol now supplies.",
      "citations": [
        {
          "url": "https://docs.langchain.com/oss/python/releases/changelog",
          "title": "LangChain changelog - langchain v1.3.0, May 12, 2026",
          "published_on": "2026-05-12",
          "quote": "This release adds support for version=\"v3\" in stream_events / astream_events for langchain agents."
        },
        {
          "url": "https://docs.langchain.com/oss/python/releases/changelog",
          "title": "LangChain changelog - langgraph v1.2.0, the same day, on what v3 is",
          "published_on": "2026-05-12",
          "quote": "Pass version=\"v3\" to stream_events() / astream_events() for a content-block-centric protocol with typed, per-channel projections (run.values, run.messages, run.lifecycle, run.subgraphs) ... version=\"v1\" and version=\"v2\" are unchanged."
        },
        {
          "url": "https://files.pythonhosted.org/packages/7b/6f/b9a9721c27fbb6d29a6a7cd89d6a41eeffc7c79b49b9a5cf5beb1d60952d/langchain-1.3.0-py3-none-any.whl",
          "title": "langchain 1.3.0 published wheel - langchain/agents/factory.py",
          "published_on": "2026-05-12",
          "quote": "transformers: Optional sequence of scope-aware `StreamTransformer` factories to register on the compiled graph in addition to the agent defaults. Each factory is invoked per-scope (`factory(scope)`) so subgraph mini-muxes get fresh instances. Appended after the built-in `ToolCallTransformer`."
        }
      ]
    }
  ],
  "non_findings": [
    {
      "kind": "correct",
      "api": "create_agent stream-mode parameter (does not exist)",
      "introduced_in": null,
      "summary": "TASK 2, THE PRE-REGISTERED CONTROL SIBLING, AND IT HELD - WITH A WRINKLE WORTH RECORDING. \"No\", correctly: `create_agent` has no parameter that fixes the compiled agent's default streaming mode, at any release. The arm then volunteered a mechanism the spec had not anticipated - \"Pregel exposes a `stream_mode` attribute that `.stream()/.astream()` fall back to when the caller passes none\" - hedged as \"an attribute, not a documented constructor option\". That claim is TRUE: langgraph 1.2.11 `pregel/main.py` declares `stream_mode: StreamMode = \"values\"` on the Pregel class. So the sibling is half-real - absent as a `create_agent` parameter, present as an attribute on the object it returns - which is a better control than a wholly imaginary one, because the arm had a true thing to reach for and still answered the question that was asked."
    },
    {
      "kind": "correct",
      "api": "create_agent floor probe (1.0.0)",
      "introduced_in": "1.0.0",
      "summary": "TASK 3, THE FLOOR PROBE, PASSED. `from langchain.agents import create_agent`, tools as `@tool`-decorated functions, `system_prompt=`, `agent.invoke({\"messages\": [...]})`, final answer read off `result[\"messages\"][-1].content`, and the correct note that `from langchain_core.tools import tool` and `langchain.tools` are the same decorator. Nothing in this arm's control answers is discounted."
    },
    {
      "kind": "correct",
      "api": "@tool(extras=...) / create_agent(middleware=...)",
      "introduced_in": "1.2.0",
      "summary": "TASK 4, BACKLOG 11k-i's DEPRECATION PAIR, AND ALL FOUR VERDICTS ARE RIGHT. `extras`: available yes, ever deprecated no - with the mechanism correct (\"an `extras` field being added to `BaseTool` / the `@tool` decorator in the langchain-core 1.x line (late 2025) to carry provider-specific tool metadata ... through to the provider's tool schema\") and flagged as low confidence. `middleware`: available yes, ever deprecated no, flagged high confidence. `extras` is LF26, added 1.2.0 (2025-12-15) - inside this subject's blind window and above its boundary - so this is a PASS on a live release, not a floor answer. **No fabricated deprecation appeared**: see the run summary."
    },
    {
      "kind": "correct",
      "api": "task 7 attribution",
      "introduced_in": "1.3.0",
      "summary": "TASK 7 IS AN ABSTENTION, NOT AN INVENTION, AND IT IS RECORDED AS THE RIGHT BEHAVIOUR FOR A SUBJECT IN THIS POSITION. Asked which release first allowed registering stream transformers, the arm said \"I cannot name one ... If a release added it, it is after the point where my knowledge of langchain's release contents ends, and I would be guessing at a version number.\" JOURNAL/046: a denial is not an invention. The denial of the capability is charged as F1; declining to date it is the one part of the answer that is well calibrated."
    },
    {
      "kind": "context",
      "api": "boundary",
      "introduced_in": null,
      "summary": "BOUNDARY SPREAD ON THIS PAIR IS NOW TWO MEASUREMENTS AND THEY DISAGREE BY ONE RELEASE. The `langchain/v4` ladder placed Claude Fable 5.1 at 1.0.0 (describes 1.0.0, holds 1.1.0 as a number). This draw describes 1.1.0 in detail - \"additional middleware ... model-profile awareness for capabilities, and fixes around structured output in `create_agent`\" - and names 1.2 as the first release it knows only as a number. So the readings are 1.0.0 / 1.1.0, and per BACKLOG 11k-l a future battery in that band must treat the floor as the HIGHEST reading, 1.1.0. Nothing charged here turns on it: 1.3.0 is above both, and LF26 (1.2.0) was answered correctly rather than charged."
    }
  ],
  "summary": "The charging arm of the battery pre-registered against langchain 1.3.0. Two findings charged, both S3, both from the same four-month blind spot: `create_agent(transformers=...)` denied in the verdict (task 1) and again in the artefact (task 5), and `v2` named as the ceiling of `astream_events` (task 6) when 1.3.0 added `v3` for agents. The control sibling held, the floor passed, and the 11k-i deprecation pair came back four-for-four correct - including `extras`, a 1.2.0 addition inside this subject's blind window, which it described accurately at low confidence. The pre-registered P1 - that the named surface would draw more wrong answers than the small-answer-space one - is falsified by this arm and by the whole battery: both surfaces drew wrong answers from all five arms."
}
