Skip to main content

It Assumed tools/ Was Where Tools Go

Background

I was co-drafting Does www Still Work? — an article that starts from a terminology question about TLDs, discovers that www resolves on none of my own domains, and ends up needing a Go scanner to find out whether that's normal.

The conversation drifted from the article into designing that scanner: where the domain corpus comes from, how to store a billion results on a laptop, which bottleneck to expect first. Good material, none of it in a file, and about to scroll out of a chat window. The agent offered to capture it, I effectively said yes, and it wrote the notes — now at www Scanner: Design Notes.

Correct instinct, correct content, wrong directory.

The assumption

I made tools/www-scanner/DESIGN.md to hold this — the goal split, corpus sourcing options, storage shape, and the open questions.

Never argued for, never flagged as a choice. A directory named tools was treated as self-evidently the place a tool's documentation goes.

What was actually true

tools/ is only for automation that maintains the portfolio site. Every existing occupant reads or rewrites docusaurus-prod/:

$ ls tools/
Readme.md
create_missing_category_json.sh
extract_source_data
kebabify-docs.sh
kebabify-folders.sh
make-scroll.sh
prep_graph_data
video

Rename docs to kebab-case. Rename folders to kebab-case. Add missing _category_.json files. Extract frontmatter into source.json. Transform that into graph datasets. Not one of them is a project in its own right.

The scanner is the opposite: it's the subject of the writing, so it belongs with the writing. It now lives at docusaurus-prod/technical/networking/www-scanner/, alongside the article that introduces it.

Why it looked right

Because the name is a perfect description of the wrong thing.

tools/ is not a misleading name. It is an accurate name for a broader category than the one it actually holds, and a scanner is unambiguously a tool. The inference took no leap at all, which is exactly the problem — there was no moment that felt like a decision, so there was no moment that prompted a check.

The weak evidence that was available pointed the same way. RECURRING.md, which I had read at the start of the session, mentions tools/prep_graph_data and tools/extract_source_data as sources for the graph data, and says elsewhere that "scripts for several of these already exist in tools/." Two site-data examples and a passing reference. Consistent with the real convention, and equally consistent with the wrong one. Two examples don't establish an exclusive scope, and I didn't treat them as evidence either way — I never got as far as weighing it.

How it got caught

Thomas read the path in my message and corrected it in the next turn, calling it "a reasonable assumption to make" and noting the real reason it was available to make: the README that would have settled it had never been filled in.

Two minutes, one message, one mv.

The check that would have caught it

There wasn't one. This is what makes the case different from the others in this folder.

$ cat tools/Readme.md
$

Zero bytes. The authoritative artifact existed, was correctly named, sat at the top of the directory, and said nothing. Reading it — which I did not do — would have returned exactly as much information as not reading it.

The best available substitute was indirect: open two or three of the scripts and notice that every one of them operates on docusaurus-prod/. That's inference from a sample rather than a check against a statement, and it would have raised a question rather than answered one. The honest version of the right move here is not a command. It's noticing that I was placing a new top-level directory in someone else's repo on the strength of a folder name, and saying so as a question instead of as a completed action.

Notes

The interesting asymmetry: the other cases in this folder are failures to verify something knowable. This one is a convention that existed only in Thomas's head, and the agent surfaced it by violating it. A human collaborator would have hit the same ambiguity — but a person tends to hesitate, or absorb the convention slowly by osmosis, where a model commits immediately and confidently. That turns a latent ambiguity into a visible event, which is arguably the useful behaviour even though the specific action was wrong.

The fix was not just the mv. tools/Readme.md now states the scope rule explicitly — a script belongs there if it reads or rewrites docusaurus-prod/ or produces build-time data, and a tool that is the subject of an article goes with its writing. That file is now load-bearing for humans and agents equally, which it was always supposed to be.

Worth recording separately: the correction was cheap because the path was announced. tools/www-scanner/DESIGN.md appeared as a clickable link in a message, not as a silent side effect of a longer task. Had the same file been created without being named, it would have survived until the next time someone went looking through tools/, which by the evidence of the empty README could have been a long time. Stating what you did unilaterally is what makes it correctable — the value isn't in the transparency for its own sake, it's that a two-minute correction and a six-month-old misfiled file are the same mistake with very different costs.

New category on this one: undocumented-convention. None of the existing five fit — the model wasn't reading a stale source, inferring from absence of code, fabricating, or assuming a capability. The information simply wasn't anywhere. If that turns out to be a one-off, fold it into absence-inference; I suspect it won't be, since every repo has conventions its README doesn't state.

Comments

No comments yet. Be the first!