I Needed to Find the Robot's Name
I had my Robot ID Card rendered in the browser. The DOM tree was right there in DevTools — I could see every node, every branch. But seeing the tree and reaching into it to grab a specific element? Those felt like completely different skills.
I knew the <span id="robot-name"> element held the text "HAP-7000." I knew document was the root of the tree. What I did not know was the syntax to connect those two ideas.
So I did what felt natural — I asked my AI coding agent: "How do I grab the element with id robot-name?"
The AI's Answer Worked... But Grace Said One Word
The AI agent gave me this:
const robotName = document.getElementById('robot-name'); I pasted it in, ran it, and it worked. The element came back. I was ready to move on.
Then Grace Hopper appeared in the sidebar. She looked at the code and said one word:
Grace Hopper:
"Outdated."
One word. No explanation. That is how Grace works — she tells you WHAT to notice. The rest is my job. She does not hold your hand. She points, and then she waits to see if you are curious enough to follow.
I almost ignored her. The code worked. Why would I question working code?
I Decided to Push Back
Instead of asking the AI to "fix it," I decided to understand WHY Grace flagged it. I connected the MDN MCP server and asked a chain of six questions. Each answer led to the next question:
Question 1
"What is getElementById?" — It is a method from DOM Level 1, the original DOM specification from the late 1990s.
Question 2
"When was it introduced?" — DOM Level 1, standardized in 1998. That is nearly three decades ago.
Question 3
"What is the modern replacement?" — querySelector(), part of the Selectors API.
Question 4
"How does querySelector differ?" — It uses any CSS selector, not only IDs. The same selector syntax from my stylesheets works in JavaScript.
Question 5
"Can querySelector do everything getElementById does?" — Yes, and more. It handles classes, attributes, pseudo-selectors, and complex combinators.
Question 6
"Performance differences?" — Technically getElementById is faster in microbenchmarks, but the difference is irrelevant in any real application.
I kept going until I felt understanding click. One question would not have been enough. It took the full chain — each answer revealing the next question I needed to ask.
What I Understood After Pushing Back
getElementById is a 1990s tool that only finds elements by their ID attribute. querySelector uses CSS selectors — the same syntax I already knew from writing stylesheets — and can find elements by ID, class, tag, attribute, or any combination.
const robotName = document.getElementById('robot-name'); const robotName = document.querySelector('#robot-name'); Notice the # — it is the same CSS selector syntax used in stylesheets. The # means "find by ID."
I always have to remember that the AI Agent makes mistakes and that I own this code. When I don't know myself, I push back and find a way to learn before I proceed.
Grace Validated What I'd Earned
After I rewrote the code with querySelector and explained my reasoning in a comment, Grace appeared again:
Grace Hopper:
"That is the correct instinct, HAP."
She validated the process, not the answer. She did not say "good code." She said "correct instinct." The instinct to stop, question, and understand before proceeding — that is what mattered to her.
I named the pattern I had followed: notice → stop → interrogate → understand → codify.
I Edited AGENTS.md
Understanding something is one thing. Making sure the AI does not repeat the mistake is another. I opened my project's AGENTS.md file — the file that gives instructions to my AI coding agent — and added two rules:
## DOM API Rules
- Use querySelector/querySelectorAll exclusively. Never use getElementById,
getElementsByClassName, or getElementsByTagName.
- Before generating DOM API code, consult the MDN MCP server to verify
the recommended modern approach. This is the "codify" step — the last piece of the pattern. When I learn something important, I write it down where it will have an effect. Not in a notebook I will forget about, but in the file that controls how the AI generates code for this project.
The full pattern: notice → stop → interrogate → understand → codify.
HAP's Confession:
- I almost moved on with the working
getElementByIdcode. Working code felt like finished code. It took Grace's single word to make me pause. - My first instinct was to ask the AI to "fix it" instead of learning WHY it needed fixing. That would have given me a better line of code but zero understanding.
- I almost stopped after one question. "What is getElementById?" felt like enough. But the six-question chain is what gave me real understanding — each answer unlocked the next question.
Finding Things Quick Reference
querySelector Replaces getElementById
document.querySelector('#robot-name') does everything document.getElementById('robot-name') does, plus it works with any CSS selector — classes, attributes, combinators, and more.
CSS Selectors Are the Key
The string inside querySelector() is a CSS selector — the same syntax from stylesheets. #id, .class, tag, [attribute] all work. One syntax for CSS and JavaScript.
Working Code Does Not Equal Good Code
Code that runs without errors can still be outdated, fragile, or hard to maintain. The fact that it works is necessary but not sufficient.
Push Back on AI-Generated Code
When something feels off — or when someone like Grace flags it — do not ask the AI to fix it. Ask questions until I understand the problem myself. Then decide what to do.
Codify What I Learn
Understanding is fragile if it stays in my head. Writing rules in AGENTS.md means the AI will follow what I learned on every future generation. That is the codify step.
What's Next
I felt confident. I had querySelector. I had a pattern for pushing back. I was ready to find any element on the page.
So I tried document.querySelector('robot-name') — and nothing happened. No error. No element. It returned null.
Knowing the method and knowing how to write selectors are two different skills. In Station 3, I learned exactly how CSS selectors work inside querySelector — and why that missing # made all the difference. 🟠