Pocock Skills
Documentation

Grill with Docs

Extract deep domain knowledge through structured questioning. Build living documentation that survives model context loss.

What This Skill Does

Grilling is a disciplined interview technique for surfacing hidden domain knowledge from a human expert and encoding it into structured, durable artifacts. The output is two things: a CONTEXT.md domain glossary and a set of Architecture Decision Records (ADRs). Both artifacts survive context resets and can be injected into any future agent session.

When to use this skill

Use Grill with Docs at the start of any engagement with a domain you do not own, before refactoring a system you did not build, and whenever you notice fuzzy or inconsistent language being used across a codebase or team.

The Grilling Interview Process

The interview runs one question at a time. Never fire multiple questions simultaneously. Each answer may reveal a better follow-up than anything you planned in advance.

1Set the frame

Tell the expert what you are building and why you need their knowledge. Be explicit: “I am going to ask you questions one at a time. For each answer I'll either follow up or move to the next topic. We are building a glossary and capturing key decisions.”

The expert should know they are producing an artifact, not just answering questions. This shifts their answers from conversational to encyclopedic.
2Ask one question at a time

Start with the most foundational term or concept in the domain. The first question is almost always: “What is the thing this system primarily tracks or manages?”

Question ordering principles

  • Start with nouns, not verbs. What are the core entities before what operations happen on them.
  • Follow the answer. If the expert uses a term you have not seen before, ask about that term next.
  • Go deeper before going broader. Exhaust one concept before moving to adjacent ones.
  • Ask for the opposite. When you understand what something is, ask what it is NOT.
  • Ask for edge cases. 'What happens when X does not match Y?' reveals invariants.
3Include the recommended answer

For every question, include what you believe the answer should be. This does three things: it shows you have engaged with the codebase, it surfaces disagreements immediately rather than at the end, and it cuts the expert's response time.

Question: What is a "Campaign" in this system?

Recommended answer: Based on the code, a Campaign appears to be a
container for one or more ad groups, scoped to a single advertiser
and billing period. Is this correct, and what am I missing?
4Distinguish use cases from definitions

Domain experts often describe how a thing is used rather than what it is. Push toward formal definitions:

  • 'That describes when it's used. What is it?'
  • 'If I had to write one sentence on a flashcard defining this term, what would it say?'
  • 'Could this term mean something different in another system? How is your meaning distinct?'
5Close each question cleanly

After each answer, do one of three things before moving on:

  1. Confirm and move: “Got it. Next question is...”
  2. Follow up: “When you say X, do you mean Y or Z?”
  3. Record a conflict: “That contradicts what I saw in the code at [location]. We should flag this as a decision point.”

CONTEXT.md — Domain Glossary Format

CONTEXT.md is the canonical domain glossary. It lives at the root of the repository. Every term that causes confusion, has a non-obvious meaning, or is used differently across the team belongs here.

Entry format

Each entry is exactly: the term, a 1-2 sentence definition, and an optional Avoid line listing synonyms the team should not use.

## Campaign

A top-level container for a single advertiser's promotional activity
within one billing period. A Campaign owns one or more AdGroups and
carries the budget ceiling for the period.

_Avoid_: "project", "initiative", "flight" — these are used
informally but have no formal meaning in the system.

## Impression

One delivery of one creative to one device, regardless of whether
the user saw it. Impressions are counted at delivery time, not at
render time.

_Avoid_: "view", "exposure" — these imply user perception, which
is not what we track.

## Conversion

A user action that the advertiser has declared as valuable, recorded
after a click and within the attribution window. The specific action
(purchase, signup, page visit) is Campaign-scoped configuration.

_Avoid_: "goal", "event" — overloaded terms from analytics tools
that mean different things in different contexts.
What belongs in CONTEXT.md
  • Any term that a new engineer would misread on first encounter.
  • Any term that means different things in different parts of the codebase.
  • Any term where the implementation differs from the plain English meaning.
  • Any abbreviation or acronym used in variable names or database columns.
  • Any business concept that has no equivalent in standard engineering vocabulary.
  • The boundary between similar concepts: when is something an Event vs a Conversion vs an Interaction?
What does NOT belong in CONTEXT.md
  • Process or workflow descriptions — those go in README or runbooks.
  • API endpoint documentation — that goes in API docs.
  • How-to guides — those go in developer documentation.
  • Implementation decisions — those go in ADRs.
Cross-referencing and linking

When a glossary entry uses another glossary term, link it inline. This makes the glossary self-navigable and surfaces definitional dependencies.

## AdGroup

A named set of [Creatives](#creative) targeting a specific audience
segment within a [Campaign](#campaign). An AdGroup owns its own
budget sub-ceiling and targeting parameters.

ADR Creation Rules

The three-gate rule

A decision earns an ADR if and only if it satisfies ALL THREE of the following criteria. If any criterion is missing, do not write an ADR.
Gate 1: Hard to reverse

The decision is difficult or expensive to undo. Reversible decisions do not need ADRs because you can simply change them. Examples of decisions that qualify:

  • Choosing a primary database or storage engine.
  • Defining the canonical data model for a core entity.
  • Adopting a particular authentication mechanism.
  • Choosing event-sourcing vs. state-based persistence.
  • Defining the public API contract for a service.

Examples that typically do NOT qualify (reversible):

  • Choosing a linting configuration.
  • Picking a test framework when others are easy to swap in.
  • Choosing between two UI component libraries that have identical abstractions.
Gate 2: Surprising without context

A developer reading the codebase without context would find this decision unexpected, suboptimal, or confusing. The ADR explains the surprise.

  • Why is the system using UUID v4 instead of UUID v7 when ordering matters?
  • Why is this service not using the standard internal auth library?
  • Why are we storing prices as integers (cents) rather than decimals?
  • Why does this endpoint ignore the standard error response format?
If the decision is what any reasonable engineer would do without further thought, it probably does not need an ADR.
Gate 3: Real trade-off

There were at least two viable alternatives, each with genuine advantages. An ADR records what was NOT chosen and why. If there was only one option, there is nothing to decide.

  • Option A gives us X but costs Y. Option B gives us Y but loses X. We chose A because Z.
  • The trade-off must be real, not theoretical. 'We could have used X but chose Y because Y is better in all dimensions' is not a trade-off.

ADR Format

ADRs are intentionally minimal. An ADR is a title and 1-3 sentences. No more. The discipline is in brevity.

The format
# ADR-001: Store prices as integer cents

We store all monetary values as 64-bit integers representing the
amount in the smallest currency unit (cents for USD). This avoids
floating-point rounding errors in financial calculations at the cost
of always requiring unit conversion in display and input layers.

Alternatives considered: decimal(19,4) in Postgres; rejected because
application-level arithmetic on floats was causing silent rounding
discrepancies in tests.

---

# ADR-002: Single Postgres instance, no read replicas

The system currently runs a single primary Postgres instance with no
read replicas. Read traffic is handled by application-level caching
(Redis) rather than database-level replication. This simplifies
deployment and eliminates replication lag as a consistency concern,
at the cost of higher cache invalidation complexity.

---

# ADR-003: Event sourcing for order state

Order lifecycle is modeled as an append-only event log rather than
a mutable state record. This provides a complete audit trail and
enables retroactive projections at the cost of requiring an event
replay step to reconstruct current state in all read paths.
ADR anti-patterns
  • Long prose explaining the decision history. That goes in a meeting note, not an ADR.
  • Decision matrices or comparison tables. One sentence on what was rejected and why is enough.
  • Status fields (proposed / accepted / deprecated). These become stale immediately.
  • Author and date headers. Git blame provides that.
  • Numbered sections with headers (Background, Decision, Consequences). The format is a title and a paragraph.

Cross-Referencing Code

After building the initial glossary, return to the codebase and run three checks.

Check 1: Terminology conflicts

Search for every glossary term and its Avoid synonyms in the codebase. Flag every location where a banned synonym is used in a variable name, comment, or database column.

# Example: search for banned synonym "view" where "impression" is canonical
grep -r "view_count|total_views|page_view" src/ --include="*.ts"

# For each result, assess: is this a UI framework "view" (acceptable)
# or a metrics "view" meaning "impression" (needs renaming)?
Check 2: Fuzzy language in documentation

Review README, inline comments, and docstrings for words like: similar, roughly, basically, kind of, usually, typically, should. Each occurrence is a candidate for sharpening.

  • 'This function roughly normalizes the input' → what does it actually do?
  • 'Users are usually authenticated by this point' → under what conditions would they not be?
  • 'This should be called after setup()' → what breaks if it is not?
Check 3: Implicit invariants

Look for code that enforces a rule without stating the rule. Add a comment or test asserting the invariant explicitly.

// Before: implicit invariant
if (campaign.budget > 0) {
  processBid(campaign);
}

// After: explicit invariant documented
// Invariant: campaigns with zero budget must not participate in bidding.
// Zero-budget state indicates a paused campaign; see ADR-007.
if (campaign.budget > 0) {
  processBid(campaign);
}

Challenging Glossary Conflicts

A glossary conflict is when two entries in CONTEXT.md contradict each other, overlap without clear boundary, or when a term in the code contradicts its glossary definition.

Types of conflicts
Conflict TypeExampleResolution
Definitional overlapCampaign and Flight share >50% of their definitionsDecide if they are synonyms (alias one to the other) or if there is a real distinction (sharpen both definitions)
Code/glossary divergenceGlossary says Event = user action; code has EventType.SYSTEM_HEARTBEATEither update the glossary to cover system events or rename the code concept
Team usage divergenceEngineering says 'Session' means browser session; product says 'Session' means a scheduled callTwo entries: Session (technical) and Session (product), both must appear in CONTEXT.md
Temporal conflictA term meant one thing pre-migration and something different nowDocument the historical meaning, mark the current canonical meaning, add a note on when the meaning changed
Resolution protocol
  1. 1State the conflict explicitly in the grilling session: 'The glossary says X means Y, but I found Z in the code at [file:line]. Which is correct?'
  2. 2Do not resolve the conflict yourself. Surface it to the domain expert.
  3. 3If the expert is uncertain, flag the entry as [CONTESTED] in CONTEXT.md and schedule a follow-up.
  4. 4Once resolved, update the glossary, then search the codebase for every instance of the losing term.

Concrete Scenario Stress-Testing

Abstract definitions fail at edge cases. After building the glossary, stress-test every entry with concrete scenarios.

The stress-test pattern

For each glossary entry, construct at least one scenario that could go either way and ask the expert to classify it.

Term: Conversion
Definition: A user action declared as valuable by the advertiser,
recorded after a click and within the attribution window.

Stress test scenarios:
1. A user clicks an ad, leaves the page, returns directly (not
   through the ad) 3 days later and purchases. Attribution window
   is 7 days. Is this a Conversion?
   → Tests: "after a click" — does the click need to be the
   direct referrer, or just the last tracked touch?

2. The same user clicks the same ad twice. They purchase once.
   How many Conversions are recorded?
   → Tests: deduplication behavior

3. The advertiser later changes the attribution window from 7 to 3
   days. Are past events retroactively reclassified?
   → Tests: mutability of conversion records
When stress tests reveal new ADRs

If a stress-test scenario requires a decision that is not already documented, run it through the three-gate ADR filter. Many ADRs emerge from stress-testing rather than from the initial interview.

Stress tests often find the ADR that should have been written but was not because the decision was made implicitly during an early sprint. Surfacing it now is valuable even if the decision is “correct.”

Single vs Multi-Context Repository Structure

Context artifacts (CONTEXT.md, ADRs) need a home in the repository. The right structure depends on whether the repo is a single-domain or multi-domain codebase.

Single-domain repository

One domain, one CONTEXT.md at the repository root. ADRs live in /docs/decisions/.

/
├── docs/
│   ├── decisions/
│   │   ├── ADR-001-integer-prices.md
│   │   ├── ADR-002-single-postgres.md
│   │   └── ADR-003-event-sourcing.md
├── CONTEXT.md          ← root-level, always loaded
└── src/
Multi-domain (monorepo) repository

Each domain/service/package has its own CONTEXT.md and ADR directory. A root-level CONTEXT.md contains only cross-cutting terms.

/
├── CONTEXT.md              ← cross-cutting terms only
├── packages/
│   ├── billing/
│   │   ├── CONTEXT.md      ← billing-domain terms
│   │   └── docs/decisions/
│   ├── campaigns/
│   │   ├── CONTEXT.md      ← campaigns-domain terms
│   │   └── docs/decisions/
│   └── shared/
│       └── CONTEXT.md      ← shared utility terms
Do not merge all domain glossaries into a single root CONTEXT.md in a monorepo. When two domains use the same word differently, the merged glossary will contradict itself.