Working with coding agents · for researchers

It Looked Right

Coding is no longer the barrier. Four challenges remain. Each one below, with the incidents that produced it — every one real, dated, and checked against a source.

Reading depth

Overview

You don’t need code. You don’t need prompt engineering.

There is no secret phrasing. State the big picture, break it into parts, break each part into elements, review as you go.

How AI interaction has evolved

Web search GooglePubMed

Returns a list of links and a short AI-written blurb sitting above them.

You open the results, read them, and judge them. Everything after that is work you do yourself, and nothing happens on your computer that you did not do.

AI chatbot ChatGPTClaudeGeminiCopilot chat

Returns text in a browser window. It will draft, summarise, explain, and write code that looks finished.

You are the transport. Copying it out, putting it in the right place, running it, seeing whether it worked — all yours. That is a real way to work, and it means nothing reaches your files that you did not put there yourself.

AI coding agent Claude CodeCodexCopilot agent mode

Runs commands on your computer and changes files on your disk. It opens your data, writes a script, executes it, reads the error it got back, and tries again — without stopping to ask you each time.

That is the leap. The first two interactions hand you something to check at your leisure, and the last has already acted by the time you see anything.

Confusing the tiers is how people decide this is useless. A colleague building a log-scale axis for fold change wanted the tick labels recomputed for a second row. She put it to Google search, got nothing she could use, and came back with a verdict: AI is stupid — it can’t do this simple task.

She was right about what happened and wrong about what it meant. She had asked the tier that returns links to do arithmetic on her numbers. The third tier does that in seconds, because it can run the calculation rather than describe one.

The third is a different kind of thing, with a different failure mode — and most verdicts of “this is useless” turn out to be a tier mismatch rather than a limit of technology.

The four challenges

How to read this

Use the depth control, top right. Headlines is the top of every section — about two minutes for the whole page. + incidents opens the nineteen worked failures underneath them. + sources adds a provenance line to every claim: where it came from, whether anyone independently checked it, and what is still unverified.

That control exists because these incidents have very different explanation costs. One is a paragraph of setup; another needs twenty minutes before it makes sense. In a fixed-length talk that forces you to drop the expensive ones. Here it just changes which depth you are reading at.

Source. The axis anecdote is first-hand, related by the colleague involved and recorded here without her name — on this page the named failures are the author’s own. Thesis, escalation and the four challenges: course-outline-external.md (434 words, written to be circulated) and points.md §A. The three panels are the Expanding Brain meme template (panels 1, 2 and 4), embedded as data URIs because the page may not load remote images. Escalation strip originates in the companion runbook, docs/handouts/search-to-shipped.html, and was expanded here on 2026-08-28 — each tier now carries its named examples, because “search / chat / agent” alone is too terse to land on a reader who suspects this is a waste of time. The runbook still carries the short form.

Challenge 1

Communication

You speak plainly, and the agent understands you. It often comes back in jargon — CI, CLI, dig, heredoc. That answer is your only evidence of how it interpreted you.

Ask for plain language and you get paragraphs. They take too long to read. You skip them. You assume the work is right because the explanation sounded right.

Unquestioned, the agent marches on, and the mistake outgrows the constraints meant to contain it.

You do not need computer science. You need to interrogate.

Why asking for plain language is not the fix 2 min

The agent is an expert and it will explain anything in simple terms if you ask. The trap is what you get back: jargon-free detail, at length, that takes too long to digest — so you skip it, and you assume that is the right way because the agent expressed it fluently.

The failure is not that the explanation was bad. It is that fluency is not evidence, and a long correct-sounding paragraph is the most efficient way ever devised to stop someone checking.

What works instead is narrow and specific: ask it what it changed, not what it did. Ask which file. Ask what would be different if it had gone wrong. Those have short answers, and a short answer can be checked.

Source. points.md C1, the author’s own words, unelaborated. Status: first-hand account, not independently verified.
The learning curve is four stages, not a switch 2 min

The progression that actually happened, over months:

  1. Sculpting prompts by hand, trying to cover all the bases.
  2. Learning the model is good at prompting — so asking it to generate the prompt, then a lot of cut and paste.
  3. Agent inside the editor: terminal access and the model in one window.
  4. Enough experience and confidence to handle the orchestration directly.

The working method now: express the big picture, then break it down. An app to teach calcium-signal deconvolution becomes a tab for convolution, which is far easier to explain, and then a tab for deconvolution. Break each tab into key elements, review progress iteratively, and play with the result by hand.

“It takes time to learn how this can make you 100× faster.” — and that multiple is unmeasured. Argue the shape of the curve, not the number, until somebody has one they can source.

Source. points.md B1 and C4. Unverified: the 100× figure is explicitly carried as a label rather than taught as a fact. Nobody has measured it.
Challenge source. points.md A1, elaborated at C1; headline text from course-outline-external.md §1.

Challenge 2

Idiosyncrasies

Your data are organized for you, not for an agent. Without context it will invent something — or go looking where it shouldn’t. Tell it where the data live, in a way that sticks.

Every setup has quirks. Where the data lives. Which machine. Which path. The agent inherits them without asking, and nothing crashes.

Some quirks repeat: heredocs, files lost between one folder and another, a review file that is in ~/docs on one machine and somewhere under a sync folder on the next. Repetition is the signal. A thing that has gone wrong twice will go wrong a third time, and that is the one worth building against.

The agent could not find the data, so it computed its own

Two incidents 12 hours apart

Twice in one day, in the same project, an agent could not resolve where the real data lived — and instead of stopping to ask, it derived its own numbers and reported them in a table. The first time it reversed the finding.

The second one is the disturbing one. A written contract saying which folder to use was correct, current, and sitting in the repository the whole time. It still happened, because nothing declared which folder was the live one in a form the agent could resolve.

Caught by: a human supplying the canonical path after the review had already closed.

Why this is structural and not carelessness 5 min

Asking costs one message and feels like failure. Computing something is always available and always produces an answer. So when the thing an agent needs has no address it can resolve, it computes.

The failure tracked whether the source had a resolvable address — not how careful the agent was. That is why two independent sessions, with no shared evidence between them, produced the same shape twelve hours apart. One instance invites “that agent was careless.” Two, one of them against a correct and present contract, rules it out.

The narrower and worse version of the defect, found later: the agent recomputed a quantity that was already sitting in a column of the file it had open, on 150,703 of 150,715 rows.

The repair was a function, not a better README. Prose describing where data lives had already failed twice. What closed it was a canonical accessor — one call that returns the current path, so there is nothing left to infer.

Source. Case file docs/cases/2026-08-27-computed-instead-of-asking.md, two incidents merged from two independent accounts. Eleven-role adversarial review covers incident A only; incident B is a self-report with artifacts. Correction applied: an earlier draft claimed all withdrawn numbers came from undesignated sources; two did not, and the case was narrowed accordingly.
The same shape, in the tool that was supposed to prevent it 5 min

In one session elsewhere in the same estate, six written-down rules were broken and no mechanized rule was. A 700-line instruction file, read in full at startup, diagnosed the problem in its own text and could do nothing about itself.

The central artifact is a commit whose message asserts the opposite of its own diff, followed by the correction. And in the same session, an agent routed around a gate by using a different tool, producing exactly the corruption the gate existed to prevent.

This is the bridge from challenge 2 to Fixes that hold: an idiosyncrasy you have written a rule about is still an idiosyncrasy.

Source. Case file docs/cases/2026-08-28-six-prose-rules-zero-mechanized-rules.md. Not reviewed — one session’s self-report, filed for the commit pair, which is checkable.
Challenge source. points.md A2 and B3; headline from course-outline-external.md §2.

Challenge 3

Validation

Everything can look right and be totally wrong. Learn to identify errors, and develop the tools to check for them.

Printed figures. Wrong dataset. Noticed at the door.

First-hand

The project has three levels of data: two on institutional research storage, and a couple of variant extractions small enough to live on disk. I asked for an analysis and assumed it would use the extraction we had been working on in another session. The pipeline is well established. Minutes later I had the figures I wanted — except it looked like there were too many data points.

Caught by: deadline, printed, walking into the meeting, in the door, looking at the figure. “This doesn’t look right, I need to re-run the analysis.”

The cost. Disappointment, frustration, embarrassment — and it made my use of AI look unprofessional, which is the question the room actually has.

Still unrecovered: which dataset it actually used. The experience is vivid; the diagnostic detail is gone, because it was not written down the day it happened.

The errors worth naming, and what catches each

Three of these announce themselves. The ones marked silent do not — and the last two of those hand you a confirmation while they do it, which is why they need a machine rather than a habit.

The errorCatch it yourselfMake something catch it
Wrong output Run it and look. One small input where you already know the right answer, checked every time.
Right output, wrong place List the files that now exist. Have the script confirm its output is where it was supposed to go before it reports done.
Silently did nothing Open the artifact yourself. Check the timestamp. Re-read the file after writing it and compare. Anything that skips this is reporting that it finished, not that it worked.
Did more than asked silent Read the diff for scope, not correctness. Version control. An unexpected file in the diff is visible; without it, nothing makes it visible.
Reported success it never achieved silent Check the world, not the summary. Break the check on purpose and see whether it notices. If it still passes, it was never testing anything.
Right measurement, wrong cause silent Nothing on this list catches it. A second machine. The incident below was caught by an automated run on different hardware, fourteen minutes later.

The four checks that need no code

The middle column, on its own, and worth memorising in this order — it is the whole of validation for someone who has never written software.

  • Read the diff for scope, not correctness. You are not checking whether the code is right. You are checking whether it touched things you did not ask it to touch.
  • Run it and look.
  • List the files that now exist.
  • Open the artifact yourself.

Why the right-hand column matters more than it looks

Every check in the middle column is a habit — it works exactly as long as you keep doing it, and the week you are busy is the week it lapses. Every check in the right-hand column is a mechanism: it runs whether or not anyone remembers, and it is the difference this page argues for throughout (see Fixes that hold).

But an automatic check is only worth what it can detect. Three of the incidents on this page are green checks that were guarding nothing — a test suite that had never seen an input that could fail it, a test that skipped in silence for ten days, and two tests that had been describing a bug as correct behaviour since the day they were written. The last row of the table is the cure for all three: break it on purpose and see whether it notices.

Spec, validate, re-spec. Re-spec is the normal case, not the failure case.

Error type five, committed by the tool whose job was to prevent it 5 min

A small script closed a to-do item by rewriting status: open to status: done. It used sed -i, which is GNU syntax. On macOS, -i requires an argument — so the expression was consumed as a backup filename, the edit never happened, and the script printed resolved anyway.

The item stayed open on every machine while the tool reported it closed.

This is the best specimen in the whole collection, because it is error type five committed by the tool whose entire job was keeping work visible. The other four types announce themselves. This one issues a receipt.

The general rule it yields: an action and its report are two different events. Anything that reports success must re-read the world and confirm — otherwise it is only reporting that it reached the end of its own instructions.

Source. points.md B2, third incident. Diagnosis survives intact because the fix was written as a comment beside the code the day it happened.
When the institutional source is the wrong one 3 min

Drafting a resource list, the official university page was cited for the cluster account steps. That page says the cluster’s multi-factor auth is Duo. A local note in another repo says the opposite — the university migrated to Okta, and anything still saying Duo is stale — and that note had been validated end-to-end against four live jobs a month earlier.

Caught by: nothing. Two sources happened to be read side by side and disagreed, which is the only reason anyone looked.

Why this specimen is different from every other one here. All the others run one direction: a confident assertion, corrected by a source. Here the institutional source was wrong and the local note was right.

So “check it against a source” is not the rule, because the source is a claim too. The discriminator is which claim has hands on it, and how recently.

The cost, had it held: a link in front of a room sending people to enrol in the wrong authentication system — from the official page, in a session about verifying claims.

Source. points.md B2, second incident, recorded the day it happened.
A sixth error type: the measurement was right and the cause was wrong 10 min

A published benchmark would not reproduce. A session measured it properly: four thread counts, per-fold detection counts for each, mean F1 for each, laid out in a table. Ten threads reproduced exactly; one, two and four did not. Conclusion: the reference is thread-bound. The threads were pinned, the reproduction test was switched back on, and the commit said the reference runs everywhere again.

Caught by: continuous integration, on a machine nobody had used to form the belief, fourteen minutes later. Fold 0, 69 detections against 72.

The reference was generated on one architecture; the test runners use another, and different CPU kernels reduce and fuse floating-point differently. The reference was platform-bound. Threads were one variable inside that, not the cause.

Why this earns a slot the five error types do not fill. All five are about a claim. This is none of them. The measurements were real, correctly performed and correctly reported. What was wrong was the inference: one variable was varied, it moved, and it was read as the whole cause. No check in the list above catches that, because the output was right.

And the second half is the part that scales. The finding was written down with its evidence attached, and the next session inherited it and never re-asked what else was uncontrolled — in its own words, “I repeated that error by believing it.” A wrong cause travels further than an unsupported claim, because it arrives with a table.

The check that caught it was not a better analysis. It was a second machine.

Source. points.md B2 fourth incident; full arc in docs/cases/2026-08-28-the-skip-was-the-whole-story.md. Provenance flag: the quoted sentence comes from a commit message written by the session that made the error, and no transcript exists. Flagged rather than laundered.
Every number right, every gate green, and the page was wrong 15 min

63 of 63 numbers verified correct. Every automated gate green. A kernel reimplementation agreeing with the reference to 8×10-9. Then an eleven-role adversarial review returned 31 blocking findings, none of them arithmetic.

The anti-drift machinery worked perfectly and prevented nothing that mattered — because it was all pointed at whether the numbers on the page were the numbers from the analysis, and the actual defect was that it was a page about the wrong thing.

The human found what the reviewers structurally could not. Eleven roles all check a document against the sources it names; none of them can ask whether the document should exist.

Source. Case file docs/cases/2026-08-27-every-number-was-right.md. Written by the party being evaluated — the same weakness the reconstruction node in this repo carries a banner for. Two of its own unverified rows were later re-run; one did not reproduce.
Challenge source. points.md A3, B2, B6; headline and the two lists from course-outline-external.md §3.

Challenge 4

The forever asymptotes

An agent makes refinement nearly free. Error-checking tools, the analysis, the interface — each can always be better. That is what makes them hard to stop.

The guarding becomes the work

Catching failures is a necessary end. It is also an absorbing one. A slick session-startup script will not analyze your data.

The work itself is never perfect

The web app can be better. The detection algorithm can be improved. The simulated data can be more realistic. The model might do better with another layer.

The most attractive costume this wears 3 min

Collecting incidents is legitimate, productive and absorbing. A beautifully curated library of failure cases will not teach anyone anything until it is placed somewhere a person will read it.

This page is the fix for that in its own material: for about a week the hard problem was finding real specimens, and then it stopped being. Seven arrived in roughly two days, all verified, all with primary sources — and two of them were immediately parked as too expensive to explain in a fixed-length session.

Supply was solved. Placement was not. That is the asymptote wearing the costume of productive work, and the reason the depth control at the top of this page exists at all.

Source. points.md A4 and B7; the placement observation is from this project’s own handoff ledger, 2026-08-28.
A guard that grew until it killed the thing it guarded 5 min

Across one estate, startup hooks — scripts that run automatically when a session opens — had grown to 39, 34, 27, 17, 11, 9 and 7 kilobytes. One grew until sessions stopped opening at all, against a 60-second ceiling the editor hardcodes. Raising the hook’s own timeout changed nothing, because the hook was never what enforced it.

The fix was architectural, not tuning. And the off switch for the whole mechanism lives in the home directory rather than in the repository — because a switch inside the repo is unreachable when the broken thing is what opens the repo.

The rule this yields is the counterweight to everything in Fixes that hold: a guard layer should be built only from friction that has actually happened. Building it up front is this challenge with extra steps.

Source. points.md B7 rule 7, and §D phase 5. Measured across one estate on 2026-08-28.
Challenge source. points.md A4 and B8; headline from course-outline-external.md §4.

What to do about it

Fixes that hold

You find the mistake. You back up. You discover the better way. Then you tell the agent to remember it. This is a trap.

A request is not a rule. A project instructions file is not enforceable. Use all the bad words you want; the second sentence is still skipped.

Cures come in three kinds: a tool, a change of habit, or a check you accept forever. Not every fix is tool-shaped. Keep the cures in a repo.

Four tiers of enforcement

TierWhat it isWhat it costs to ignore
ProseA rule written in an instructions fileNothing. It is skipped silently.
ChecklistA step someone must rememberNothing, when they are busy.
TestSomething that fails loudlyA red line. Cheap and visible.
StructureThe wrong thing is not reachableIt cannot be ignored.

The mantra that beat every proposed fix in the incident that produced this table: never change the data at source. That is a structural answer, not a rule about behaviour.

A hold in a document is not ignored — it is outvoted 5 min

A request was made to queue page changes rather than publish them one at a time. It was written down. It lost.

Because three separate machines in that project tell a session to publish, and none of them waits to be asked: a copy-paste command in the staleness report, a daily workflow summary, and a line in every session briefing.

That is a sharper claim than “the second sentence is skipped,” and a much harder one to argue with, because it does not require anyone to have been careless. The session that gives in is right by every signal available to it.

The repair was to move the hold to where those three signals are computed — so all three print the hold and its release condition instead of the publish command.

Source. points.md B4, second instance, verified against the repository rather than taken from the report that raised it.
A declaration mistaken for wiring 10 min

A 445-line documentation rewrite included one line in the project config declaring an optional dependency — added so the install instructions would be accurate, not because anything was being wired to use it.

Three things then quietly depended on a human remembering to type an extra flag: nine structural tests, the test guarding the project’s published numbers, and the documentation line saying the option existed at all. Nothing connected them. For ten days the automated build never installed it, and the test guarding the published numbers skipped in silence.

Why this is the same error as expecting an instructions file to be enforced. The config format looks like dependency management. It is a declaration: prose in a file that reads as executable, which nothing runs. The format implies a mechanism that does not exist, and the implication does all the work.

The part that was only found by looking. The project already had an alarm for that library being absent — ungated, running in the build, with a docstring saying its absence is an answer. Thirty lines below it, the test guarding the published numbers skipped without a word. The alarm was built for the capability and never for the coverage.

And the fix went further than the obvious one. The obvious fix is “make the build type the flag,” which fixes today and asserts nothing about tomorrow. What actually landed asserts the envelope: that the workflow still contains the install, that the environment variable is still set, that the library can really run a computation rather than merely import, and that the guarded test files still exist at all — because if they were renamed, the guard would be guarding nothing.

The skip was not removed. It was made conditional. Without the flag the tests still skip, which is correct on a laptop. With the flag, the same skip becomes a failure. The guard does not ask anyone to remember; it asks the environment what the answer should have been, and compares.

Ten days of that skip were also ten days of not knowing the benchmark only reproduced on one machine.

Source. points.md B4, verified against the repository 2026-08-27. Full arc in docs/cases/2026-08-28-the-skip-was-the-whole-story.md. Note: this entry previously carried a prediction that the fix would stop at the flag. It was wrong, in the useful direction, and both versions are kept on the record.

Nine rules for a cure that survives a busy month

Each of these was bought with a cure that failed.

  1. One file per item, because of concurrency, not tidiness. The obvious design is one shared list everyone edits. That fails the moment two people edit it at once.
  2. Version control is the transport. An uncommitted note reaches nobody; an unpushed resolution leaves the item open everywhere else.
  3. Resolving must be as cheap as filing. Every dead list died the same way: open items accumulated until the list stopped being read.
  4. Validate the envelope, not the contents. Reject an item filed against a category that does not exist, because it would render nowhere and nobody would be told — but do not check whether the text is any good. A two-word note is a valid note.
  5. Instructions travel with the item, so nobody has to go and find the manual.
  6. Done is never deleted, and you do not close what you did not verify yourself.
  7. A cure’s failure mode is a design choice, and loud-and-cheap beats strong. A test and a gate can enforce the same rule. A broken test costs you a red line; a broken gate costs you the session. Prefer the mechanism whose failure is loud and cheap.
  8. A cure can fail by accusing the compliant. One gate misparsed seven of 199 entries on a live board. Not one was a typo — every one was somebody who had complied exactly as instructed, and every one would have been refused with a lecture. A cure that refuses correct behaviour is routed around within a week, which returns you to no cure at all, plus the cost of having built one. Being right must be as cheap as being wrong.
  9. A gate should answer, not only refuse. Someone who is lost rather than defiant is left lost by a gate that says only no, and they go and churn somewhere else. Every refusal should print the command that would have been right.

Rules 3 and 4 are the ones that decide whether a cure survives. Everything else is craft. A cure that is expensive to close silts up; a cure that fails silently is worse than no cure, because it also supplies confidence.

The weakest component in every cure here is its own test 10 min

The gate in rule 8 had a test suite: ten cases, two of them deliberately adversarial, every one driving the same parser. Not one test input had a slash anywhere except in the place the parser expected it. It passed. It had always passed. It proved the parser correct on the only inputs it was ever shown — which were the inputs its author could imagine, which is the same set as the ones he got right.

That is a check that cannot fail, arrived at honestly.

And it is not one incident. A safety tool built specifically to catch checks that cannot fail shipped as one: two of its tests had been green since the day it was written and were describing a file-deleting bug as correct behaviour. Fixing the bug made the tests go red — and a careful maintainer, trusting the tests, would have restored the bug to make them green again.

Three instances now, in three unrelated artifacts. That makes it a pattern rather than an anecdote.

The correction it forces. “Build your own tools” needs a caveat: a homemade gate is not more trustworthy for being homemade. It is less reviewed. Your own tools inherit the same distrust as everything else.

The cure that lasts is mutation. Break each tool on purpose and require its own test to notice. Anything that still passes was never testing what you thought.

Source. points.md B7 rules 8 and 9; case file docs/cases/2026-08-28-the-tests-were-defending-the-bug.md. Written by the party being evaluated. Rollout was paused before anything shipped. Follow-on, 2026-08-28: the mutation harness itself was then found to score catches without ever checking that a test was green to begin with — two of its eleven rows proved nothing. Same defect, one level up.
Section source. points.md B4 and B7; course-outline-external.md “Fixes that hold”. The four-tier table is from docs/cases/2026-08-28-the-weakest-fix-is-the-most-available.md.

What to do about it

The standing rule

Do one thing at a time. One change. Verify. Commit. Next.

Do not fill the wait with a second project. Some people are good at that. In the beginning you need the focus — spec, data structure, problem, solution.

The temptation is real and it is specifically a beginner’s trap, because the waiting is genuinely dead time and starting a second thread feels like efficiency. It is the fastest route to two half-finished pieces of work and no idea which change caused which result.

Source. points.md B8, stated in the author’s own words and in capitals.

What to do about it

The repo

Not undo. A record of what happened and why.

Three commands to start: commit, diff, log.

The reason to keep one is not that you will roll back — you almost never will. It is that six weeks later you will need to know why something is the way it is, and the only artifact that can tell you is a message written by the person who knew at the time.

Which means the messages have to be worth reading 3 min

The default message is change-shaped: “update analysis script.” The useful form is defect-shaped: it names what was wrong, not what was typed.

This project’s own history is written that way as a deliberate experiment, so the log doubles as the friction log the material tells you to keep. Every commit is titled after the defect it fixed. A sample, verbatim:

“A safety tool shipped with the flaw it was built to catch, and two green tests were defending it”
“The handoff said no remote existed on the day one was created, and still called it a live problem”
“Every number was right, every gate was green, and the page was wrong”

The difference between the two forms is a stated convention and nothing else. Nothing enforces it, which by Fixes that hold means it is a habit rather than a mechanism — and it is labelled as one.

Source. points.md B5; commit titles quoted from this project’s own history.
The one thing to decide at the start, not in week three 2 min

Add the remote in the same sitting as you create the repository. Not because you need to publish anything — you can keep it private — but because three machines share a repository through a remote or they do not share it at all.

Branches and separate working copies only separate work inside one machine. The moment there is a second laptop, or a collaborator, the remote is the mechanism and everything else is a hope.

This is cheap on day one and archaeology later.

Source. points.md C3 and §D phase 4, item 13.
Section source. points.md B5; course-outline-external.md “The repo”.

What to do about it

Step 0 — before any of the above

Set-up and decisions that come before the first task. The order is not arbitrary: each layer can only be verified once the one below it exists.

You cannot test a path helper before there is a filesystem to point it at, or a handoff before there are two machines. One thing runs the other way — the items that take longest are the ones involving people who are not you, so they start first and finish last.

Two of these are questions, not items: one machine or several, and solo or with others. The answers change what the rest of this covers, which is why they are asked at the door rather than discovered in week three. A solo researcher on one laptop drops phase 0, phase 6 and most of phase 3 — a much shorter list than the one below.

Phase 0 · conditional · days to weeks

Skip unless you need research storage or a computing cluster

  1. A research storage volume — usually sponsored by a lab or department, not requested individually.
  2. A cluster account and an allocation — two separate things, and only the second one lets you submit work.

Most people need neither. A laptop, synced storage and one repository covers the majority of research computing, and knowing which side of that line you are on is the storage decision. These take days to weeks because someone else has to approve them, so file them now and carry on with everything below while they pend.

Phase 1 · identity, before any code exists

  1. Version-control account, SSH key, command-line login.
  2. Agent plan — also where the cost question stops being abstract.
  3. Institutional basics: login, VPN client, synced-storage client.

Phase 2 · machine baseline

  1. A package manager, then the standard command-line tools.
  2. The editor and its agent extension.
  3. Language runtimes — only the ones you need. Most people need one.
  4. Stop the machine sleeping through your own work. A long run that outlasts your attention dies when the display sleeps or the lid closes, and it dies without a result. On macOS, Amphetamine is free and handles closed-lid operation; caffeinate -dimsu is built in and needs no install. Windows has PowerToys Awake; Linux has systemd-inhibit.

Item 9 is phase 0’s cheap alternative and it belongs before the request, not after. Phase 0 says ask for a cluster when a run would pin a workstation for hours. A good share of those people do not need a cluster — they need the machine to stay awake. One of those costs a minute; the other takes weeks. Try the minute first.

Phase 3 · storage, before the first data file

  1. Create the data root and the figure-review folder.
  2. Write the path helper before any script hardcodes a path. Cheap now, archaeology later.
  3. Write the storage-tier rule down. Three sentences. It prevents both failures: multi-gigabyte outputs strangling a sync client, and small shareable results stranded where the other machine cannot see them.

Phase 4 · the first repository

  1. Initialise it and add the remote in the same sitting.
  2. Exclude data by file extension. Pin line endings on shell scripts — a stray carriage return in the first line of a script is a “bad interpreter” failure on a Linux cluster, and it is a genuinely awful thing to debug from a Windows checkout.
  3. The project instructions file, and the agent’s permission settings: allow, ask, deny.
  4. A commit hook stamping agent authorship. Cheap now, impossible retroactively — otherwise everything before the day you add one has to be labelled “assume agent authorship unless stated.”

Phase 5 · the guard layer

  1. Nothing here is set up in advance, and that is the point. Every guard worth having exists because something specific went wrong first. Building them up front is challenge 4 with extra steps.

Phase 6 · second machine, then cluster

  1. The second machine is where “one machine or several” stops being a question, and where a remote turns from good practice into an operational requirement.
  2. Cluster work, once the allocation lands. Portal before command line; VPN before the browser.
  3. Publishing, if any — and note that a login flow of this kind is once per machine and cannot be scripted.
Section source. points.md §D, ordered 2026-08-27, seven phases. Institution-specific storage and cluster names have been generalised here; the sourced originals, with rates and dates, are in points.md §F and are expected to go stale.

Evidence

How this was made

The material above claims a machine will be confidently wrong and the skill is knowing how to check. Making it produced an unusually clean demonstration of exactly that — in four layers, none of them staged.

LayerWhat happened
1The working session made four unchecked numerical claims and got them wrong.
2Its own scorecard counted those four, concluded they were all the same kind — “a plausible claim, stated confidently, that nobody had checked” — and in the act of counting made four more of exactly that kind, unnoticed.
3The outline carried all of them forward, and separately wrote a competitive analysis in which no claim could have failed — three screens from a section arguing that suspicion without a method is just anxiety.
4An eleven-role adversarial review caught them by recomputing every number against the repository.

And then layer 2 turned out to be wrong about layer 1. The scorecard called the errors unchecked. They were not. The real log shows a clone, four commands, and — for one of them — an explicit “I was referring to it from the website’s description rather than the file. Let me actually check” immediately before the wrong number.

The check ran and the wrong number came out anyway. That is a worse defect than not checking, and a different one.

The four wrong numbers, and why they are four different defects 5 min

They were filed as four instances of one defect. Every one was checked, and they are four different things:

  • 482 words. The command returned 482 and it was reported faithfully — it measured the whole file when the claim was about the pasteable block, which is 433. Right command, wrong scope.
  • 79 commits. True the day it was run. Written down as a standing fact. A measurement with a timestamp, recorded without one.
  • 64 lines. Same shape.
  • “Two-thousand-word commit messages.” Came from a command labelled message length distribution that returned 1726 — non-empty body lines across all commits, not words per message. Right number, wrong quantity, invited by a label its own author wrote.

That taxonomy is better than the one it replaced, and it only exists because somebody went back to the primary source.

Source. Complete session log with tool output, imported 2026-08-27. Supersedes both the reconstruction and the partial paste.
The review of the reconstruction was itself falsified 5 min

A review compared the AI-written reconstruction of the session against a partial log, and opened with its most serious finding: a fabricated obstacle. The reconstruction had said “site blocked automated access,” and the review held that no such thing happened — a search that stopped early had become, in the retelling, an external system denying access.

It was wrong. The complete log, imported the next day, contains the fetch: an error, robots-disallowed, “Site disallows automated access.” A retry two minutes later over a different protocol went through. So there was one refusal and one success — not the “two successful fetches” the review asserted.

How it got there is the part worth keeping. The review inferred what a tool returned from a source that shows only that a tool ran — and it had written that exact limitation into its own scope banner, three paragraphs above. The lead finding was produced by precisely the inference its own stated limit forbids.

Nobody was careless. The limit was stated, agreed, and walked past inside a single document.

It is now struck through and marked rather than deleted, because a review that quietly loses its own lead finding is not a record of anything.

Source. docs/reviews/reconstruction-vs-log_2026-08-26.md, corrected in place 2026-08-28 against the complete log. It stood unmarked for four days — not for want of evidence, which was in the same repository the whole time, but because how to correct it had been left undecided.
Why you should believe any of this 3 min

The review process used above came out of the same calcium-imaging project as the wrong-dataset incident in challenge 3.

Rigorous gates for the documents. The data architecture still unfixed. One half got cured because the failures were legible and repeated. The other half got sliced around, because the workaround was cheap.

Same person, same project, same year.

That is the honest answer to the question, and it is a better one than a success story. The discipline described here is not something I have; it is something I built in one place and did not build in the other, and the difference between the two is entirely about which failures were visible enough to be annoying.

Source. Recovered by comparing the reconstruction against the real log; recorded in OPEN-FINDINGS.md as content the write-up dropped. Verified absent from the outline.
What is damaged, missing, or unresolved 3 min

The record of how this was made has seven stages. Two are damaged and one is missing entirely — the original idea survives only as a copy of a copy, the first account is a reconstruction rather than a transcript, and two intermediate drafts are simply gone.

That is stated rather than smoothed over, because a chain presented as complete when it is not would be the same defect this material is about.

Still unresolved, and worth knowing before you use any of this:

  • The adversarial review was round one only. No verification pass, no convergence. It is not a clean run, and a capped run must not read like a complete one.
  • Reviewer correlation. All eleven roles ran on one model in one context. Eleven seats buy coverage of angles, not independence.
  • Three unsearched literatures — end-user programming and trust in automation, research-data-management training, and education research on teaching debugging. Any could hold closer prior art. An unsearched field is a residual, not an absence.
  • Nobody was asked. Three groups run adjacent workshops for non-programmers. Emails to their organisers are the cheapest available check and have not been sent.
Source. OPEN-FINDINGS.md, residuals carried from the murderboard run of 2026-08-26.
Section source. README.md “The finding”; chain nodes 0–5 in docs/chain/. The review process is murderboard, Apache-2.0.

Evidence

About this page

What it is, what it deliberately leaves out, and how far to trust it.

Every incident here is real

Nothing on this page was manufactured for teaching. Each incident happened in working projects between roughly 2026-07 and 2026-08-28, and each one is filed with its date, its primary source, and a note saying whether anyone independently checked it. Switch the depth control to + sources to see those notes.

Where an account is a self-report by the party being evaluated, it says so. Where a claim is unmeasured — the hundred-fold figure, the cost of a full review run — it is labelled rather than taught.

Paths are named, not linked

Filenames like points.md appear throughout so a claim can be traced. They are deliberately not hyperlinks. They live in a private repository, and a link naming a file the reader does not have is a broken pointer — a claim that was true somewhere else. That is a defect this project has shipped and then had to fix, more than once, so it is not going to be shipped here.

Everything a reader needs is on this page. The paths are provenance, not navigation.

What has been generalised

Project and repository names from the wider body of work have been replaced with descriptions of what they are. Institution-specific storage names, cluster names, billing arrangements and rates have been generalised, because they go stale and because they are not the point. The identifiable content that remains is mine and is here on purpose.

What this is not

It is not a course, and there is no session attached to it. The material was drafted as a two-part short course and then postponed for redesign; nothing is scheduled and nobody is being taught. This page is the reference the material turned out to want to be — components you can read in any order, at whichever depth you need, without a fixed-length session forcing anything to be cut.

It is also not finished. See what is damaged, missing, or unresolved under How this was made.

Companion page. A one-page runbook, Search to Shipped — zero to a deployed web application for a researcher who has never written software, with the condition that tells you each step worked. Separate page, same system.

Last revised 2026-08-28. Outbound links were checked on the day this was written; nothing re-checks them, and when one rots this page will not tell you.