Context Engineering
Week 5 · The specification is the context
Week 5 · The specification is the context
Who has pasted a whole file into a chat window this semester?
Who has pasted more than one?
"Add a createdAt timestamp to the new entity."
The agent writes:
this.artifact.setCreatedAt(LocalDateTime.now());Except in this repository.
America/ChicagoLocalDateTime.now() bypasses all of it, silentlyNo comment at the call site. No compiler error. No failing lint.
From backend/CLAUDE.md:
All time-dependent code must inject the
Clockbean and useLocalDateTime.now(clock), neverLocalDateTime.now().
That line is context engineering. No prompt would have produced it.
Moffatt v. Air Canada
Booking after his grandmother's death, he asks the airline's chatbot about bereavement fares.
The bot says: you can apply retroactively.
The airline's actual policy
Said the opposite.
It was published on the same website.
The chatbot is a separate legal entity, responsible for its own actions.
The tribunal called this "a remarkable submission":
While a chatbot has an interactive component, it is still just a part of Air Canada's website.
Week 2
The repository is the team's shared memory, and the only memory the agent has.
Weeks 3 and 4
You wrote the glossary, use cases, business rules, and the specification.
Week 5: that specification is the context. Now learn to aim it.
Connecting Slack gives your agent more text, not better context.
The same is true of your repository.
Everything competes for the same fixed space:
| Model | Advertised window |
|---|---|
| Claude Fable 5.1, Opus 5.5, Sonnet 5 | 1M |
| GPT-5.x | ~1M |
| Gemini 3.1 Pro | 1M |
| Gemini 3 Pro, Llama 4 Scout | 10M |
| Claude Haiku 4.5 | 200K |
As of September 2026. These move constantly.
Quality does not hold to the ceiling. Plan on 40 to 50 percent of the number on the box.
On a 1M model, that is 400K to 500K.
Every context window is advertised the way a laptop battery is. Technically ten hours. Bring the charger.
Selection is the work
Somebody decides which lines this task needs.
If you do not, the agent does, by guessing.
Relevance decays with volume
Padding makes the signal harder to find.
The cost lands on your most specific instruction.
"I gave it the whole repository" is not an answer to "did it have what it needed?"
/context |
How much room is left |
/compact |
Summarize and keep going. /compact focus on <topic> keeps the detail you name |
/clear |
Wipe the conversation, keep your login |
Claude Code compacts on its own as the window nears its limit. Copilot CLI starts at about 80%.
/clear. Do not carry a summary of unrelated work into the next one.That last one is week 2's thesis, now with a keystroke attached.
It searches it.
Claude Code builds no index. It runs the tools you would:
Nothing hands it the query. Where does the query come from?
The model writes the query, the same way it writes code. It guesses what string would appear in code that does this thing.
What it knows generally
A Spring Boot service is *Service.java. A getter is getX.
Training data, not your project.
What it has read this session
Your charter. The directory listing. Its own last three results.
"Why does a student with no evaluations show 0.0?"
| Turn | Move | Where it came from |
|---|---|---|
| 0 | reads CLAUDE.md |
automatic |
| 1 | glob **/*Evaluation* |
your word "evaluations" |
| 2 | narrows to EvaluationService |
logic lives in the service here |
| 3 | grep "average" |
your other word |
| 4 | reads getPeerEvaluationAverage |
found it |
"peer evaluation average"
Turn 1 greps PeerEvaluation.
83 hits. Four turns to the method.
"peer review score"
Turn 1 greps peerReview.
0 hits. The codebase says PeerEvaluation.
A miss does not stop it. It widens, reads five wrong files, and gets there with your window part full.
The query is assembled out of your vocabulary. Naming consistency is the hit rate.
The glossary fixes vocabulary. Use the defined term in code identifiers and UI text, never a synonym.
Project Pulse's requirements module is the package ram/.
Ask about "requirements authoring" and the agent greps requirementsAuthoring. 0 hits.
What repairs it, one line in the root charter:
a Requirements Authoring & Management (RAM) module
That is a charter doing search-enablement. It is also why this course makes you spell abbreviations out.
If you know which file it needs, point at it. @path/to/File.java
Naming the file skips the search.
The alternative: it guesses a grep pattern, reads three wrong files, and arrives at the right one with your window part full and your credits part spent.
Every wrong guess costs tokens you paid for and context you now cannot use for the answer.
Point at it
"Fix the bug in @EvaluationService.java"
You know. Don't make it hunt.
Let it search
"Find where peer evaluation averages are computed"
You don't know. Pretending you do costs more.
The honest way to save tokens is not shorter prompts. It is fewer wrong guesses.
Before
Thin user story meets a human developer.
Gaps filled from hallway conversation, intuition, "we all know how this works."
Now
Thin user story meets something that has none of those.
Gaps are not filled. They are guessed, fluently.
A vague requirement used to cost you a conversation. Now it costs you code.
| Durable | Per-task | |
|---|---|---|
| Artifact | The agent charter | The issue for one use case |
| Written | Once, then grown | Every time |
| Scope | Everything true of the project | One unit of work |
| Read | Every session | When you point at it |
Everything the agent needs for one unit of work, gathered in one place.
In this course: the place is the issue, the unit is one use case.
Cite the specification. Never copy it.
You have manufactured the exact drift the method exists to prevent.
From the root charter, pointing at the architecture document rather than restating it:
When the architecture changes, update that doc; the summary below is just orientation for working in the code.
flowchart LR
CH["Agent charter<br/>durable, read every session"] --> S(("Agent<br/>session"))
ISS["Issue<br/>the build-context"] --> S
ISS -. cites by ID and path .-> UC
ISS -. names .-> CODE["Files it will touch"]
subgraph SPEC["The specification, cited and never copied"]
direction TB
UC["UC-AREA-slug"]
BR["BR-slug"]
SRS["Quality attributes"]
end
UC -. Business Rules .-> BR
UC -. Associated Information .-> SRS
SPEC --> S
CODE --> SOnly the residue:
Writing a paragraph that belongs in the specification? Put it in the specification. Then cite it.
Context engineering is a selection problem, not an accumulation problem.
Twenty minutes. You know the drill.
The Registrar wants to text students when a seat opens in a full course section they are waiting on. Last spring about 4,000 students watched at least one full section, most of them for a handful of popular MWF morning sections. The registration system is a vendor product the university cannot modify; it offers a read-only seat-count feed that can be queried at most once a minute per section. Students sign up for alerts on a new page, and whoever registers first after the text gets the seat. It has to be live for spring registration in November, and the Provost has said it will "end the refresh-button problem."
Five minutes. Alone, silently. No agent, no neighbour, no phone. Six lines: shape, hard part, bottleneck, stack, three kill risks, verdict.
The agent's napkin on this brief is pasted here before class.
Every line where you and the agent differ is a piece of context one of you had and the other did not.
The Clock rule from the start of the hour.
Also: the three services and their start order, the dev credentials, and the fact that dev recreates the schema on every restart while production runs Flyway migrations.
From backend/CLAUDE.md:
Extend these packages, don't fork the architecture for RAM.
Code records what was built. It never records what was ruled out.
An agent imitates what it sees. Two conventions in one codebase, and it copies the nearest one, confidently.
From frontend/CLAUDE.md:
Use entity-first, PascalCase, multi-word names. NOTE: some existing pages use verb-first naming (e.g.
AddActivityForm.vue,EditStudentForm.vue), these should be refactored to entity-first in the future.
The glossary fixes what a word means. The business rules fix who may do what.
Both are cited, never restated. Which is why weeks 3 and 4 insisted on them.
And Monday gave you the mechanical reason: the glossary is what makes the agent's first search land.
How do you know when you have supplied enough?
How thorough the prompt felt.
How long the issue is.
How confident you were.
All three are uncorrelated with whether the agent had what it needed.
Sufficiency is a property of the result. So measure it on the result.
Well-contexted
Asks few questions. It can find the answers.
Badly contexted
Asks none. It cannot tell what it is missing, so it invents.
Silence is ambiguous.
Disambiguate it: ask for its assumptions before it writes any code.
Assumptions you did not supply and did not intend are your gap list.
From Project Pulse's root charter:
The spec is authoritative but not infallible. When a step is ambiguous, an assumption breaks against the existing code, or requirements contradict, ask a clarifying question or challenge the spec; don't silently comply or silently invent.
A question from the agent is the cheapest defect report you will ever get. It arrives before the code exists.
Shift+Tab in Claude Code until the status bar reads plan mode on, or type /plan.
Plan mode works out what it intends to do, and shows you, before it touches a file.
Copy last week's activities into this week Students retype the same activities every week. Add a button on My Activities that copies last week's activities into the current week so they only have to update the hours.
What in this plan did nobody tell it?
Not this
"Is this plan safe?"
That is a code-review question, and you are not reviewing code yet.
This
"What is in here that I never told it?"
A file you did not mention. A rule you never wrote down.
The plan is a gap list that wrote itself.
When to use it: multi-step work, context you are unsure of, changes that are expensive to unpick.
When to skip it: a one-line fix, where reading the plan costs more than reading the diff.
Compare what it built against what you wrote. Every difference is one of two things:
A defect in the code
Fix the code.
A gap in the context
Fix the context.
The failure mode is fixing the code and leaving the gap. Then the next use case arrives with the same defect.
A written rule leaves a trace in what gets built. So audit it.
| Built | Pages | Convention |
|---|---|---|
| Foundation, before the charter | AddActivityForm.vue, EditActivityForm.vue, CommentActivityForm.vue, EditStudentForm.vue, SubmitTeamsEvaluations.vue |
Verb-first |
| RAM, spec-first under the charter | RamDocuments.vue, RamDocumentEditor.vue, RamGlossary.vue, RamUseCases.vue |
Entity-first, 4 of 4 |
And the note warning that the old code disagreed is what stopped the agent copying the nearest precedent.
Plausible, and wrong.
An issue that specifies every method signature has a name. It is called "the code", and we already own a tool that turns that into a binary.
If guessing it wrong would violate a requirement, the specification pins it. Otherwise the agent derives it.
Derived
Column lengths, indexing, nullability, the internal shape of a service.
Pinned
Key formats, status transitions, validation rules, anything a business rule constrains.
Week 2 told you to write the charter thin, and said it would grow.
This is how it grows.
Project Pulse's backend charter, in its own margins:
It had drifted.
PATCH /users/{userId}was bound to a manager that recognised only/students/,/instructors/and/evaluations/evaluators/, so it denied every request from the day it was written.
Every cross-team defect found in September 2026 was one of the two missing: the glossary routes had neither; the document-section GET had a scoped query but no rule; the artifact and use-case lookups had a rule but no scoping.
Not a principle the agent can agree with. Something it can act on:
The smell to grep for: a service method that accepts
Integer teamIdand never mentions it in the body.
A charter that never grows is a charter nobody is learning from.
Then the assembly is worth packaging: a skill, a file that carries the steps.
Week 7, where the design and implementation gates give one something to do.
Write them by hand first. A wrapper around a thing you have never done teaches you the wrapper.
Details: Studio, week 5
Who got a reminder email on Monday, for something you had already submitted?
Project Pulse emails every student in the section. Nothing checks whether you already submitted.
You can specify this and an agent cannot, because you have received the email and it has not.
Due Friday, October 2, moved from Sep 25. Fork tcu-cosc-40943/spec-a-feature.
Graded on your decisions and your edge cases. Not on whether anything ran.
Selection, not accumulation. Cite, never copy. Measure the result, not the prompt.