Step 3 · The Loop · The Loop · Loop Engineering ENPT
Module 2 · The Loop · Step 1 of the cycle

LEARN: see the real state, do not assume

The loop opens with one move that decides everything after it: look. Before you change a thing, read the current state, the scope, and the trusted sources — and inspect the real artifacts with your own eyes. The cheapest way to wreck a whole cycle is to start from a guess.

Read the plain version, or open the technical layer on any section.
1

The big idea: look before you leap


Every turn of the loop has five steps — LEARN → ANALYZE → EXECUTE one bounded unit → VERIFY at the real boundary → DECIDE. This lesson is about the first one. LEARN means you stop and find out where things actually stand right now before you touch anything.

That sounds obvious, and it is exactly the step people skip. Under time pressure it is tempting to remember how the code used to look, picture what the file probably says, and start typing. The loop forbids that. You read the current state, you re-read the scope (the measurable "done" from the last lesson), you pull in any trusted sources you need, and you open the real artifacts — the file, the log, the test output, the page — before you decide a single thing.

Why so strict? Because a guess at the start poisons every step after it. You will analyze a gap that is not there, execute a change against a file that no longer matches your memory, and "verify" against the wrong thing. One bad assumption at step 1 can burn an entire cycle. A few seconds of looking is the cheapest insurance you will ever buy.

One more rule that matters across this whole course: when LEARN needs a fact from the outside world — a current version number, what a tool actually does, whether something is still true — you do not reach into memory and hope. You get it from a trusted source. In this suite, live web facts always come from the Bright Data CLI (you will meet it in lesson 11), never from guessing, and never from a stale recollection.

Think of it like… a surgeon before the first incision. They do not operate from the chart they remember from last week — they re-scan the patient today, confirm the site, count the instruments. Looking is not a delay before the "real" work; it is the work that makes the rest safe. Where the analogy breaks: a surgeon looks once; in the loop you LEARN again at the start of every pass, because the state changed the moment you last touched it.

What "state" means precisely

State is everything the next decision depends on, and it is bigger than "the code". It includes the artifact you intend to change (file contents, current function bodies, config), the boundary that will judge the change (test results, a running process, an HTTP response, a build), the scope contract (the done-when), and any external facts the work leans on (a library's real API, a current price, a spec). LEARN reads all four — not the ones you happen to remember.

Reading, not running, the cycle yet

LEARN is strictly observational. You are not making a change here and you are not yet deciding what the change will be — that is ANALYZE (lesson 4). Keeping LEARN pure matters: if you start editing while you are still discovering the state, you have lost the ground truth you were trying to establish. Observe first; classify second; act third.

The anti-assumption rule

Treat every belief you hold from memory as stale by default and confirm it against the artifact. "The handler returns JSON" → open the handler. "Tests pass" → run them. "The package is on v3" → check, via Bright Data if it lives on the web. The discipline is not pessimism; it is refusing to let an unverified claim sit at the root of a decision tree.

2

What LEARN actually reads


LEARN is not one thing — it is a short checklist of inputs. Read the current state of the artifact, re-read the scope (your measurable done), pull in trusted sources for any outside fact, and inspect the real artifacts instead of trusting a summary of them. Here is the anatomy.

LEARN observe, do not assume Current state file · config · code now Scope contract the measurable done-when Trusted sources Bright Data, not memory Inspect artifacts open it, run it, read it ANALYZE next step (lesson 4) grounded facts →
Four inputs feed LEARN; its output — a grounded picture of reality — is what ANALYZE is allowed to reason over.
read current state re-read scope trusted sources only inspect, don't summarize observe, don't edit
3

In one picture: read before you act


The whole rule fits in a single line of flow. Reality goes in; you observe it; only then do you decide. The forbidden shortcut — the dotted red arrow — jumps straight from "I have a task" to "I'll act", skipping the look. That shortcut is exactly what the loop exists to stop.

A task arrives "change X" The real state files · logs · output OBSERVE LEARN — look at both DECIDE from facts, not guesses ACT one bounded unit the assumption shortcut — skips the look, poisons everything after
Read left → right. The solid path observes first; the dotted red path is the one the loop forbids.

The one rule

No decision in the loop is allowed to rest on a fact you did not look at. If you can't point to where you saw it, you don't know it yet — you assumed it.

4

Assume vs inspect, three ways


This is the core of the lesson, so we will land it three different ways: a side-by-side picture of the two habits, a little simulator you can hammer to feel how assuming drifts while inspecting stays true, and a step-through of the read-before-act decision itself.

ASSUME from memory "it probably…" picture drifts ≠ reality decision on sand cycle wasted vs INSPECT from the artifact open · run · read picture matches = reality grounded decision cycle counts
Same task, two habits. The only difference is where the picture came from — and that difference compounds.

Feel it. Below, the same task comes back round after round (the loop runs many passes). The left agent assumes the state hasn't changed and keeps acting on its first picture; the right agent re-inspects every round. Press Next round a few times and watch the gap open up.

Assumes the state

Memory agent

Looked once on round 1, then trusted that snapshot forever. Never re-reads the artifact.

Stale beliefs
0
Picture is fresh — it just looked.
Waiting for the first round.
Inspects each round

LEARN agent

Re-opens the artifact at the start of every round, so its picture can never go stale.

Stale beliefs
0
Picture is fresh — it just looked.
Waiting for the first round.
Rounds elapsed: 0

The world changes every round (other agents commit, logs rotate, the page updates). Only the agent that re-looks keeps a true picture.

Memory agent — never re-reads

let picture = read_state();   // round 1 only

function onRound() {
  // acts on the FIRST picture forever — drifts as reality moves
  return decide(picture);
}

LEARN agent — re-reads every round

function onRound() {
  const picture = read_state();  // fresh every pass — never stale
  return decide(picture);
}

The fix is almost insultingly small: move the read_state() call inside the loop. That is the entire difference between an agent whose picture rots and one whose picture is always current. LEARN is that call, made on purpose, at the top of every pass.

Walk the decision. When a task arrives, LEARN runs a tiny gate: do I actually know the current state? Each "no" sends you back to look; only a clean "yes" lets you proceed. Pick a situation and step through it.

Trace situation:
yes yes yes no → look no → look no → look A task arrives Read the state? Trusted source? Still current? ✓ Proceed to ANALYZE ↺ Go look first
Read top → bottom. Each "no" routes you back to looking; only a clean run earns the right to act.
Step 0 of 4

Start here

A task lands

Press Next to walk the just inspected case. Switch the situation above to see how a guess gets sent back to look.

5

Read the state, end to end


What does "read the current state" look like in practice on a real repo? It is a short pipeline of its own — five quick reads that take you from "I have no idea" to "I can see exactly where things stand". Follow the table of contents down the page.

What a LEARN pass moves through


You land in an unfamiliar repo with a task: "make the search handler reject empty queries". Before you can decide anything, your eyes travel through five reads: orient (what is this project?), open the artifact you'll change, check the boundary that will judge you, re-read the scope, and ground any outside fact. Each read replaces a guess with a fact.

Think of it like… walking into a kitchen you've never cooked in before a dinner rush. You don't start chopping — you find the layout, open the fridge to see what's actually there, check the stove works, read the order ticket again, and confirm an ingredient you're unsure of. Then you cook.

LEARN reads → Orient what is this? Artifact open the file Boundary run the test Scope re-read done External ground it five reads → one grounded picture, handed to ANALYZE
Read left → right: each box is a read, not an edit. Nothing is changed until all five are done.
1Open the artifact you intend to change read

Don't picture the handler — open it. The current body might already validate input, might not exist, might be named something else entirely. You only know which after you read the actual bytes on disk today.

2Check the boundary that will judge you run

Run the tests now, before changing anything. A failing test you didn't cause is part of the state; a suite that's already red tells a very different story than one that's green. This baseline is what VERIFY (lesson 6) compares against later.

3Re-read the scope contract read

"Reject empty queries" — does that mean whitespace-only too? Return a 400, or empty results? The done-when from lesson 2 settles it. Re-reading scope at LEARN time stops you from solving a slightly different problem than the one agreed.

4Ground any external fact verify

If the fix depends on what a library actually does, or a current convention, you confirm it from a trusted source — the Bright Data CLI for anything on the web (lesson 11), never a half-remembered API. An unverified external fact is just another assumption wearing a confident voice.

In the code: the reads, made real


Here is what those reads look like as the actual commands a LEARN pass runs. Notice every line is a read — nothing edits, nothing commits. This is observation, captured.

a LEARN pass — all reads, zero writes
# 0 · orient — what even is this repo?
ls -1 ; cat README.md
git log --oneline -5            # recent history = part of the state

# 1 · open the artifact you plan to change
grep -rn "def search" services/search/
sed -n '1,40p' services/search/handler.py

# 2 · check the boundary BEFORE touching anything
pytest services/search/ -q       # baseline: is it already green?

# 3 · re-read the scope contract (the measurable done)
cat GOAL.md                       # done-when lives here

# 4 · ground an external fact from a TRUSTED source
brightdata search "flask request.args empty value handling"

Access it yourself

Find the entry point with grep -n "def search" services/search/handler.py, then read just the top with sed -n '1,40p' services/search/handler.py rather than loading the whole file into your head.

Get the test baseline with pytest -q (or your project's runner) before you edit — that output is state. For any web fact, the path is always the Bright Data CLI: brightdata search "…" or brightdata scrape <url>; never WebSearch/WebFetch, never the Bright Data MCP. That rule is taught in full in lesson 11.

6

Three honest ways to inspect


"Look at the state" is not one technique. Depending on what you need to know, you reach for a different tool — and each makes a trade between how fast it is, how deep it goes, and how much of reality it actually touches. None is "the" right answer; the skill is picking on purpose.

A

Search (grep / find)

Sweep the whole tree for a name, a string, a definition — to find where something lives before you read it.

# where is it defined? where is it used?
grep -rn "def search" services/
grep -rn "normalize(" services/

Pros

  • +Fast: scans a huge repo in a blink.
  • +Maps the territory before you commit to reading.

Cons

  • Shows location, not behavior — never the full story.
  • Easy to match the wrong thing and feel sure.
Pick this when You don't yet know where the relevant code or config is. Start here, then open what it points to.
B

Read the artifact

Open the actual file and read the real bytes — the current body, not the version in your memory.

# read the real thing, today
sed -n '1,60p' services/search/handler.py
cat services/search/config.yaml

Pros

  • +Ground truth for structure and intent.
  • +Catches what changed since you last looked.

Cons

  • Slower; easy to drown in a large file.
  • Says what code should do, not what it does.
Pick this when You know where it is and need the real structure and logic before deciding on a change.
C

Run it / observe output

Execute the real boundary — tests, the process, an HTTP call — and watch what actually happens.

# what does it REALLY do right now?
pytest services/search/ -q
curl -s "localhost:8000/search?q="

Pros

  • +Touches reality: real behavior, real failures.
  • +Gives the baseline VERIFY will judge against.

Cons

  • Needs a runnable environment; slowest to set up.
  • Tells you that it fails, not where in the code.
Pick this when Behavior is the question — "does it actually reject empty input?" Reading can't answer that; running can.

Right now I most need to know…

Combine them — they answer different questions

A real LEARN pass usually uses all three in sequence: search to locate, read to understand structure, run to confirm behavior. Skipping any one leaves a blind spot — reading without running is the classic trap, because the code can look perfectly correct and still fail at the boundary. The fourth "way", for facts that live outside the repo, is never guessing: it is the Bright Data CLI, the single uniform path every agent has to live web evidence.

7

The state snapshot: read it at a glance


Once you've looked, it helps to hold the state in one view — what you actually know, what's only partial, what's still unknown, and what you're (dangerously) assuming. This is a status report for your own understanding. Hit Refresh to take a new reading, or turn on Live to watch it move as a run progresses.

Think of it like… a control-room dashboard before you flip any switches. Green means you've confirmed it; amber means you've half-looked; red means you're flying blind. You don't act on the red rows — you go look at them first.

State of knowledge — RHG search-handler task

repo: rhg-platform · branch: fix/empty-query · LEARN pass

State is well understood
last looked just now
Facts confirmed
7/9
+2 looked
Assumptions left
1
−3 verified
Boundary read
green
baseline set
Scope re-read
yes
done-when clear
Per-item knowledge state
What we need to know State Confidence How we looked

One model, two views

A single array of "things we need to know" drives both the table and the rollup pill. Each refresh confirms a little more (an assumption becomes known once you actually look), recomputes each item's state, then re-derives the banner: any unknown → red, any assumed → amber, else green. The deltas are coloured by meaning — fewer assumptions is good (green) even though the arrow points down.

Why "assumed" is its own state

Most dashboards have known / unknown. LEARN adds a third, sharper one: assumed — a belief you're treating as fact without having looked. It reads amber, not green, on purpose. An assumption is a debt; the snapshot keeps it visible until you pay it off by inspecting.

8

Capture what you observe, before you classify it


While you LEARN, you'll notice things — a confusing function, a failing test, a missing dependency, a risky bit of code. The discipline is: write each one down as a raw observation first, in the Observed column. Don't judge it yet. Only after you've finished looking do you confirm it's real, and later classify it (that's ANALYZE's job, next lesson). Capturing first stops you from acting on a half-seen thing.

Press a card's arrow to move it one step, or drag it. The counts stay honest — every observation is in exactly one column.

Think of it like… a detective's evidence board. You pin every clue as you find it — no theory yet. Pinning is not concluding. Only once the wall is full do you start drawing the lines. Decide too early and you'll bend the next clue to fit the theory.

Open observations: 0 · Classified: 0
Observed0
Confirmed0
Classified (→ ANALYZE)0

Observations are state, not decisions

The board is a tiny state machine. Each observation is one object with a col field that can only be observed, confirmed, or classified. The columns on screen are not the source of truth — the array is. Keeping Observed separate from Classified enforces the lesson at the data level: a thing must be seen and confirmed before it earns a category. Classification (priority, type, what to do) is ANALYZE's job in lesson 4; LEARN only gathers.

Because the UI is rebuilt from state on every change, the counts can never drift, and a card physically can't be in two columns. Same shape as any kanban — Jira, Linear, Trello — minus the network. One array, one render, native drag events.

9

Where LEARN sits in the loop


LEARN isn't a one-time setup step — it's the gate every pass of the loop goes through first. To feel that, drive the loop yourself below. Notice you can't jump straight to EXECUTE: the only move available from the start is LEARN. The machine refuses the illegal shortcuts, exactly like the discipline does.

again → LEARN ANALYZE EXECUTE VERIFY DECIDE

The clay-filled node is where you are now. Faint nodes aren't reachable from here.

Current step

LEARN

Read the real state, scope, and trusted sources. You can't analyze or execute until you've looked.

Allowed moves

Step log

    The loop as one object

    The order isn't a suggestion — it's a transition table. From LEARN the only legal event is analyze; you cannot execute before analyzing or verify before executing. Try it: the illegal buttons grey out. Modelling the loop this way is what makes "look first" structural rather than a thing you have to remember.

    const loop = {
      LEARN:   { analyze: 'ANALYZE' },
      ANALYZE: { execute: 'EXECUTE' },
      EXECUTE: { verify:  'VERIFY' },
      VERIFY:  { decide:  'DECIDE' },
      DECIDE:  { again:   'LEARN' }   // next pass re-LEARNs
    };

    The loop returns to LEARN, never skips it. Every pass re-establishes the state, because the act of executing on the last pass changed that state.

    10

    Worked example: learning a small repo before changing it


    Let's tie it together on one concrete task, start to finish — the LEARN part only. The task: "In the RHG service, make /search reject an empty query with a 400 instead of returning all results." Watch how a careful LEARN pass turns four guesses into four facts before a single line is written.

    guess → fact 1"The handler is in handler.py"

    grep -rn "def search" services/ returns services/search/api.py:42 — not handler.py at all. The guess was wrong by one file; acting on it would have meant editing the wrong place. Fact: the handler lives in api.py.

    guess → fact 2"It probably returns early on empty input"

    sed -n '40,58p' services/search/api.py shows it does not — an empty q falls straight through to index.lookup(""), which returns everything. Fact: there is no guard at all; that's the actual gap.

    guess → fact 3"The tests are green"

    pytest services/search/ -q11 passed, and there's already a test test_empty_query_returns_400 that's skipped. Fact: the boundary is green and a spec for the fix already exists, waiting to be un-skipped. VERIFY now has its target.

    guess → fact 4"Flask gives empty params as None"

    Unsure, so confirm it the only allowed way — brightdata search "flask request.args.get empty string default" — which shows a missing ?q= yields None but ?q= yields "". Fact: the guard must catch both None and empty string. A memory-only answer would have missed the empty-string case.

    What LEARN produced

    Four facts, zero edits: the real file (api.py:42), the real gap (no guard), the real boundary (green, with a skipped spec), and a grounded external fact (catch both None and ""). ANALYZE can now reason over reality instead of a story. That is a LEARN pass done right — and it took under a minute.

    The pass, as it would land in LOOP-LOG.md

    A LEARN pass leaves a trail the human can observe later (this is the observability the whole suite runs on — you'll see it in lesson 7). Reads only; every claim has a source.

    # LEARN — fix/empty-query
    grep -rn "def search" services/   # → api.py:42  (not handler.py)
    sed -n '40,58p' services/search/api.py   # → no empty-q guard
    pytest services/search/ -q          # → 11 passed; 1 skipped (the spec)
    brightdata search "flask request.args empty string"  # → None AND "" possible
    # state established → hand to ANALYZE. no files changed.
    11

    Quick check: did it stick?


    Recall beats re-reading. Answer each from memory before you peek — the option you pick grades instantly, with a note on why. No tells in the formatting; the answers are spread around on purpose.

    Q1What is the single job of the LEARN step?

    Q2You need a current fact that lives on the web. What do you do?

    Q3Why run the tests before you change anything?

    Q4During LEARN you spot a failing test. What's the right first move?

    Q5Why does the loop re-run LEARN at the start of every pass?

    Score: 0 / 5
    Your agent is your teacher. Stuck on why "assumed" is treated as dangerous, or want to run a real LEARN pass on your own repo? Ask. Next up — once the state is grounded — is turning that picture into one ranked move: ANALYZE: classify the gap, rate, pick ONE unit.