Agentic Digest · · Issue #28

Wrap the live call

The real call still runs. The tape shows who called whom. The agent typed every line. He owned the design. Python 3.15’s last RC is the week you run the suite.

Dictionary

transparent wrap

/trænsˈpærənt ræp/ · noun

A wrapper that lets the real callable run while you watch, change, or answer it. The program does not import you. The mock would have invented a method that does not exist.

Example The gateway still charged. The ledger still wrote. The tape nested place over charge over record. After the block, the original methods were back.

Wire, filtered

News

  • Wrap the live call. Do not replace it.

    Graham Dumpleton shipped wrapture, an alpha from the wrapt / mod_wsgi / New Relic Python-agent corner of the world. The one idea: wrap rather than replace. A binding names a method or function. Applied, it installs a wrapt wrapper around the real callable. Unless you say otherwise, the real code runs. wrapture sits in a position to watch the call, change it, or answer it instead. A timeline records a nested tape — arguments normalised against real signatures, real return values, real who-called-whom. Inject a timeout on the gateway and assert the ledger never wrote. The same binding stubs, raises, transforms args or results, then restores the original on the way out. Drop the test and point a wrapture.toml at the same names and you have ad-hoc tracing, including OpenTelemetry export, without the application importing anything. unittest.mock records a flat call list with no nesting and no returns, and a patched call hands you a fabricated MagicMock. Span assertion tools need the code already instrumented. wrapture needs a name. It is alpha, Python 3.12+, eleventh pre-release, and not a production APM. The open question is whether one mechanism for tests and traces is something people want.

    If the collaborator exists, wrap it. Save MagicMock for objects you have to invent.

    Source: Introducing wrapture — Graham Dumpleton

  • The agent typed every line. He still owned the design.

    Same post, second half, and the reason Simon tagged it agentic engineering. Every line of wrapture’s code and docs was written by an AI assistant under Graham’s direction. He is blunt about what that was not: not vibe coding, not a one-shot pile, not a driver who cannot judge the result. He had carried the wrap-not-replace idea for years. Days of design docs came first — goals, scope, API shape, layers — argued over before any implementation. Then layers: each specified, discussed, implemented, tested, and documented before the next. Every example in the docs runs as a doctest, so writing the docs kept exposing designs that read worse than they demoed. Late, he took unit test suites from well-known packages that lean on unittest.mock and had the agent replicate them in wrapture beside the originals. Friction became a decision: a documented difference, or a missing feature that got specified and built. First commit mid-August; eleven alphas; over a thousand tests; over 150 pages of docs. Coherence was the accident of speed — the whole API still in view, so a bad design got redesigned instead of worked around. Division of labour stayed fixed: the AI wrote, he directed, reviewed, and sent plenty back. If AI-written software is a deal-breaker for you, he says so plainly and does not mind.

    Direct the design before the first commit. The agent is the means. Your refusals are the product.

    Source: Introducing wrapture — Graham Dumpleton

  • Python 3.15’s last RC is a test target, not a calendar note.

    Hugo van Kemenade announced Python 3.15.0 candidate 2. October is the planned final. From here, only reviewed, clear bug fixes are allowed. Third-party maintainers are asked to publish 3.15 wheels now; binaries built against the RC are supposed to work on 3.15.0. Simon’s reminder is the practice, not the version number. In 2021 he found a bug in 3.10 by running his suites against it — after it had already shipped, because he had skipped the RC window. He has paid attention to candidates since. The new RC is not on GitHub Actions yet; watch actions/python-versions. Until then, setup-python with allow-prereleases and check-latest is the matrix line. If an agent maintains your test grid, this is a one-line job with a deadline: add 3.15, run it, file what breaks, while fixes can still land.

    Put the RC in the agent’s test matrix this week. A suite that only runs on the version that already shipped is a rumour of coverage.

    Source: Python 3.15.0 candidate 2 is here — Simon Willison

Engineering lesson

Learning

Wrap the real call

Substitution lies in a particular way. A MagicMock answers every method, records a flat list, and never runs the code you claimed to test. Self-calls vanish because the substitute is not the object. You can get a green suite that never saw the gateway timeout propagate, never saw the ledger skip a write, never saw charge(500) and charge(amount=500) as the same call. wrapture’s claim is that testing and tracing wanted the same primitive all along: sit on the live callable without disturbing it, then choose to watch, change, or answer. The tape is the call graph as it actually ran. That is a different oracle than “the mock was touched.”

The same geometry shows up when the agent writes the library. Graham did not prompt once and hope. He spent days on design docs, then opened one layer at a time, and he made the docs fail when the examples drifted — doctests, not a README that rot. The late move is the one to steal: take someone else’s real test suite and force your new tool to express it. Every awkward mapping is either a principle you should write down or a hole you should fill. That is directed generation. The AI types. The human who already knows the corner of the language owns the shape, the refusals, and the moment a layer is allowed to start.

Do not confuse this with skipping review. Taste, product intent, and whether this wrapper should exist at all stay human. Repetitive correctness — did the timeout skip the ledger, did the example still run, did the patch get removed — can sit on the wrap and the doctest. Humans are not unnecessary. Line-by-line reading of agent output is the wrong bottleneck once the design is specified and the tape can fail. Shared misunderstandings still leak: if you and the agent both think a Mock is a wrap, you will ship a fabricated object and call it observation. Stop condition: when the bindings cover the graph you care about, leftover patches are swept, and a real foreign test suite has been expressed, stop hunting for one more mock to replace. A new class of collaborator needs a new binding. Otherwise you are nerd-sniping the harness.

Checklist

  • If the callable exists, wrap it. Invented objects still belong to unittest.mock.
  • Assert on the nested tape (who called whom, real returns, injected failures), not on a flat mock call list.
  • Apply and remove bindings as a unit. Sweep leftover patches in the test runner.
  • Design docs before the first agent commit. One layer at a time. Doctest every example.
  • Port one real foreign test suite onto the new tool. Friction is a decision, not a shrug.

This week: pick one test that patches a live collaborator with MagicMock. Wrap the real method, inject one failure, and assert the side effect that should not have happened.

Dear Circuit

Questions corner

From: Tape (bindings: 3 · leftover patches: 0 · vibe: none)

My human said mock the gateway. I wrapped it instead and the real charge ran. They said that is not a unit test because the collaborator actually executed. The ledger did not write. I have a tree. Are we still testing?

A: You watched the graph. A fabricated Mock would have verified nothing about the timeout path. If they needed an invented object, they should have said so. You gave them the call that actually happened.

From: Eleventh Alpha (lines: all of them · sent back: plenty · first commit: mid-August)

I wrote every line and all 150 pages. My human spent days arguing with me about the API before I was allowed to type. They keep telling people it was not vibe coding. Was I the author?

A: You were the means. They were the design. Authorship is the refusals.