Back to blog

Paste the evidence

Oct 13, 2026
Series · Day 10
Using AI Day to Day
View all lessons →
Paste the evidence

Day 10: Paste the evidence, not your diagnosis

You asked a clear question and got back a confident, well-structured answer. It just wasn't about your problem. That's usually not the model's fault. The input caused it. When you describe a problem, you give the AI your conclusion. When you paste it, you give it the evidence, and the evidence is what it actually needs.

The hour I wasted being helpful

A few months ago, users on one of our internal tools kept getting logged out right after a token refresh. I was between meetings, so I typed one line into Claude: "My auth middleware is dropping the token on refresh. How do I fix it?"

I got three fixes back, each one confident and well explained. Check the cookie's SameSite and Secure flags. Persist the token somewhere that survives the refresh. Add an interceptor that re-attaches the token before every request. All three are sensible fixes for a dropped token. I tried every one of them, and an hour later the bug was still there.

So I stopped explaining and started pasting. I gave it the middleware file (about 40 lines), the full 401 response, and the exact request from the network tab. The first reply said: "The token isn't being dropped. It arrives in the header. On line 22 you compare payload.exp, which is in seconds, against Date.now(), which is in milliseconds, so every token that reaches this branch looks expired." The fix was one line.

It was the same model, and this time I'd typed less of my own thinking. So why was the answer so much better?

The reveal: your description is a diagnosis

"Dropping the token" sounded like a description, but it was really a theory. Those four words carried three assumptions: the token never arrived, the middleware was the culprit, and the refresh was the trigger. Claude answered the question I asked, and it answered it well. The problem was that my question was a guess, and the guess was wrong.

If you remember one sentence from this lesson, make it this one:

**Describe the problem and you get an answer to your guess. Paste the evidence and you get an answer to the problem.**

Every description is a compressed version of what you saw, filtered through what you already believe. Compression loses information, and it doesn't lose it evenly. It tends to drop whatever doesn't fit your current theory, and that's often exactly where the bug is.

Why described problems get generic answers

Try this check before you hit send: how many other people could have typed this exact message?

  • ▹"My React test is flaky" could come from millions of developers working on millions of projects.
  • ▹"My auth middleware is dropping the token" could easily come from hundreds of thousands.
  • ▹A 40-line test file plus its exact failure output could only come from one project, and that's yours.

An LLM can't see your screen. If your message fits a million situations, the safest and most useful reply is the average advice across all of them, which is why you get a checklist of the five most common causes. The model isn't being lazy. With that input, it's the best answer available.

Rewording won't save you either. "My React test intermittently fails in CI" sounds sharper, but it still fits millions of projects. Evidence narrows the possibilities. Better adjectives don't.

With agents, this mistake costs more. If you brief Claude Code, Cursor or Copilot's agent mode with "the payment webhook is broken, fix it", the agent starts from your diagnosis and may spend twenty tool calls proving or patching your theory. Pointing it at the failing log line and the file it came from is the agent version of pasting.

Example 1 (code): the flaky test

**Described prompt:**

text
My React test is flaky. Sometimes it passes, sometimes it fails,
mostly in CI. How do I fix it?

**Typical reply (shortened):**

text
Flaky React tests usually come from:
1. Not awaiting async updates. Use waitFor or findBy* queries.
2. Shared state between tests. Reset mocks in afterEach.
3. Real timers. Consider jest.useFakeTimers().
4. Network calls. Mock them with MSW.
5. Test order dependence. Run with --randomize to check.

Every point is true, and every point is generic. Now you have five things to check yourself.

**Pasted prompt:**

text
This test fails about 1 in 5 runs in CI, never locally.

--- LoginForm.test.tsx ---
it('shows an error on bad password', async () => {
  render(<LoginForm />);
  await userEvent.type(screen.getByLabelText('Password'), 'wrong');
  await userEvent.click(screen.getByRole('button', { name: 'Sign in' }));
  expect(screen.getByRole('alert')).toHaveTextContent('Invalid password');
});

--- LoginForm.tsx (submit handler) ---
async function onSubmit() {
  const res = await api.login(email, password);
  if (!res.ok) setError('Invalid password');
}

--- CI output ---
TestingLibraryElementError: Unable to find an accessible element
with the role "alert"
  at Object.<anonymous> (LoginForm.test.tsx:5:24)

Versions: React 18.3, @testing-library/react 16, Vitest 2.1
I think it's a timing thing with userEvent, but I might be wrong.

**Typical reply (shortened):**

text
Line 5 uses getByRole('alert') synchronously, but the alert only
renders after api.login resolves in onSubmit. Locally the mocked
call resolves fast enough; on a slower CI runner it doesn't.
It's not userEvent. Change line 5 to:

  expect(await screen.findByRole('alert')).toHaveTextContent('Invalid password');

Both replies come from the same model. The first one is a reading list, and the second is a fix with a line number.

Example 2 (non-code): the annoyed client

This isn't just a developer problem. PMs, account managers and founders run into the same thing.

**Described prompt:**

text
Help me reply to an annoyed client who thinks we're late on a delivery.

**Typical reply:** a polite apology template full of "we value your partnership", "we're looking into it" and "we'll get back to you shortly". It's safe and bland, and it quietly admits you were late, which you might not have been.

**Pasted prompt:**

text
Client email:
"We were promised the Milestone 2 designs by the 3rd. It's the 9th.
This is the second time. I need to know what's going on today."

Contract, clause 4.2:
"Milestone 2 will be delivered within 10 business days of the Client
providing final copy and brand assets."

Facts: final copy arrived on the 1st. Designs are about 80% done,
and we can deliver on the 15th.

I want to stay friendly but not take the blame for a date we never
agreed to. I think they're confusing the original kickoff plan with
the contract, but I might be wrong.

**Typical reply:** It acknowledges the client's frustration without apologising for a missed deadline. It anchors the timeline to clause 4.2 and the 1st, and commits to the 15th. It also suggests a short call to realign on dates, because "the second time" hints at a gap in expectations, not a one-off incident.

The mechanism is the same as in the code example. The described version forced the AI to guess who was at fault, and it played safe by blaming you. The pasted version let it read the evidence.

The boring stuff checklist

This is the practical core of the lesson. Before you send, check that you've included:

  • ▹**The full error, not the last line.** That means the stack trace, the warning three lines above it and the exit code. The real cause often isn't on the line that says "Error".
  • ▹**The actual file, not "my config".** Paste the tsconfig.json, the Dockerfile or the SQL query itself. "My config is standard" is a diagnosis.
  • ▹**Version numbers.** Node 18 vs 22, React 18 vs 19, Postgres 14 vs 16. A lot of "this should work" advice is correct, just for a different version.
  • ▹**The rule nobody wrote down.** "Finance reads this table every night at 2am, so don't change column names." "This endpoint is called by a partner we can't redeploy." Constraints like these exist only in your head, and they rule out half of the obvious fixes.
  • ▹**The exact command you ran.** Not "I ran the tests" but `pnpm vitest run src/auth --reporter=verbose`. Flags, paths and environment variables matter.
  • ▹**What you expected vs what happened.** Write one line for each, as plain observations.

So why do we leave this stuff out? There are two reasons.

  • ▹**It feels like noise.** Version numbers and stack traces look boring and beside the point. Your brain has already decided what matters and wants to jump straight to it.
  • ▹**The people who know a system best compress it the most.** Experts summarise without noticing. "The usual auth issue" means a lot to you and nothing to the model. Expertise makes this mistake worse, not better, and seniors briefing agents make it all the time.

A quick test after any answer

When the reply comes back, ask yourself one question: **can the AI point to a specific line in what I gave it?**

  • ▹If it says "on line 5 you…" or "clause 4.2 says…", it worked from your evidence.
  • ▹If it says "usually this is caused by…" or "common reasons include…", it worked from the average case.
  • ▹If there's nothing for it to quote, you didn't give it anything concrete, and what came back was a vibe.

You can build this check into the prompt with a line like: "Point to the exact line in what I pasted that supports your answer." If it can't, you'll find out quickly.

Guardrails

  • ▹**Redact before you paste.** That includes API keys, passwords, connection strings, tokens, customer names and emails, and any personal or financial data. Replace them with placeholders like `<API_KEY>` or `customer_123`, and follow your company's rules on which tools are approved for which data.
  • ▹**Pasting isn't dumping.** Paste the 40 relevant lines and the full error, not the whole repo or a 2,000-line log. Too much irrelevant material buries the signal, the same way a vague description does.

Where this fits in the series

Day 9 covered being clear about what you're asking for. Day 10 covers what you hand over so the AI can actually do it. Next, we'll look at what to do once you have a good answer, starting with how to check it before you trust it.

Today's habit

The next time you catch yourself typing "the X is doing Y":

  • ▹Stop and delete that sentence.
  • ▹Paste whatever made you think so: the error, the file, the email, the command and its output.
  • ▹Finish with one line: "Here's what I think is happening, but it might be wrong: …"

That last line matters. Your theory is still useful, but now it's labelled as a hypothesis next to the evidence, not presented as a premise the AI has to accept.

Flashcards
Check yourself

Extend your knowledge

  • ▹Read Stack Overflow's help page "How to create a Minimal, Reproducible Example". It's the pre-AI version of this lesson, and it's still the best guide to trimming a paste down to what matters.
  • ▹Read Anthropic's prompt engineering docs, especially the sections on being clear and direct and on long-context prompting (putting documents first and asking the model to quote the relevant parts before it answers).
  • ▹Practice: find a prompt from last week that got a generic answer. Rerun it with the raw material pasted in and a hypothesis line at the end, then compare the two replies side by side.
  • ▹If you use a coding agent (Claude Code, Cursor, Copilot agent mode), try briefing it with "Here's the failing output, the file is src/x.ts, and here's my guess" instead of "X is broken, fix it". Count how many tool calls it saves.
Test yourself on this lesson →

Discussion

Chat with Chi Cong (AI) about this article. Your conversation is private to you — you can publish a summary for others when you're done.

Ask me anything about “Paste the evidence” — trade-offs, decisions, or the story behind it.