Code Comprehension Part 1: Hypotheses & Beacons
Part 1 of a two-part code comprehension tutorial for students who have completed the Python, React, and Node.js essentials tutorials. Practice deciding where to focus attention, reading faster with beacons, and verifying only the code that matters in a roughly one-hour session.
Purpose Hypotheses
Why this matters
When code feels overwhelming, the slowest move is often reading from the first line and hoping the purpose emerges. Strong readers start with a hypothesis: “This code probably does X, and these are the places that would prove or disprove it.” That is not guessing. It is evidence-seeking with a plan.
🎯 You will learn to
- Generate a purpose hypothesis before tracing code line by line
- Select which file or function deserves attention for a specific question
- Summarize code at macro, function, and block levels
The Basic Routine
Use this loop whenever you meet unfamiliar code:
- Orient: read the file name, public function, test names, and comments that describe intent.
- Predict: say what responsibilities you expect to find.
- Beacon-hunt: scan for names, tests, data shapes, and familiar code plans.
- Descend selectively: inspect the smallest region that can answer your question.
- Verify: trace one path, map one test, or check one invariant.
- Summarize: explain the code above the line-by-line level.
When to Switch Gears
Top-down reading is not permission to trust names blindly. Use beacons to choose where to look, then switch to bottom-up tracing when the evidence gets risky.
| Cue | Good next move |
|---|---|
A beacon is vague, like data or item |
Trace a small local chunk |
| A branch handles errors, hiding, or totals | Trace one representative input |
| A test contradicts your first hypothesis | Revise the hypothesis before reading more |
| Syntax is unfamiliar | Understand that small expression first, then return to the purpose |
Explain in Plain English
A strong answer is not the longest answer. Use this short EiPE-style frame:
| Part | What to say |
|---|---|
| Purpose | What the code is for |
| Mechanism | The main plan it uses |
| Evidence | The names, tests, or branches that prove it |
| Limit | What input, edge case, or behavior you have not verified yet |
Line-by-line narration can be useful while tracing, but it is not the final product. Your final explanation should be relational: how the pieces work together to serve the purpose.
In this step, the Python files show a tiny playlist summarizer. Do not start by tracing every expression. Start from the tests and the public function name.
Worked Reading Example
Suppose the question is:
“Does the summary include hidden tracks?”
A bottom-up reader might trace every line. A hypothesis-driven reader does this:
| Move | What to read | Why |
|---|---|---|
| Orient | test_summary_uses_only_visible_tracks |
The test names the behavior in student-friendly language |
| Predict | Expect a filtering step before summary construction | Hidden tracks should be removed before labels and totals are computed |
| Beacon-hunt | visible_tracks, hidden, summarize_playlist |
These names are evidence about responsibility |
| Descend | Read visible_tracks() and where summarize_playlist() calls it |
That is the shortest path to the answer |
| Verify | Trace one hidden track through visible_tracks() |
One path is enough to confirm the hypothesis |
Variable Roles
Names become stronger beacons when you can say the role each value plays.
| Variable | Role |
|---|---|
public_tracks |
Filtered collection used by the rest of the summary |
total_seconds |
Accumulator result used to compute minutes |
label |
One display string for one visible track |
Your Turn
Read test_playlist_summary.py first, then scan playlist_summary.py. Write a one-sentence hypothesis:
“This module probably…”
Then answer the knowledge check. You do not need to edit the code.
from typing import TypedDict
class Track(TypedDict):
title: str
artist: str
seconds: int
explicit: bool
hidden: bool
class PlaylistSummary(TypedDict):
track_count: int
minutes: float
labels: list[str]
TRACKS: list[Track] = [
{"title": "Compile Me Maybe", "artist": "Carly Rae JS", "seconds": 181, "explicit": False, "hidden": False},
{"title": "Null Pointer Mood", "artist": "The Exceptions", "seconds": 203, "explicit": True, "hidden": False},
{"title": "Draft Demo", "artist": "Lab Notebook", "seconds": 92, "explicit": False, "hidden": True},
{"title": "Cache Me Outside", "artist": "Miss Hit", "seconds": 228, "explicit": False, "hidden": False},
]
def visible_tracks(tracks: list[Track]) -> list[Track]:
return [track for track in tracks if not track["hidden"]]
def label_track(track: Track) -> str:
label = f"{track['title']} — {track['artist']}"
if track["explicit"]:
label += " (explicit)"
return label
def summarize_playlist(tracks: list[Track]) -> PlaylistSummary:
public_tracks = visible_tracks(tracks)
total_seconds = sum(track["seconds"] for track in public_tracks)
return {
"track_count": len(public_tracks),
"minutes": round(total_seconds / 60, 1),
"labels": [label_track(track) for track in public_tracks],
}
if __name__ == "__main__":
print(summarize_playlist(TRACKS))
import math
from playlist_summary import summarize_playlist
TrackFixture = dict[str, object]
def make_track(
title: str,
seconds: int,
*,
artist: str = "The Testers",
explicit: bool = False,
hidden: bool = False,
) -> TrackFixture:
return {
"title": title,
"artist": artist,
"seconds": seconds,
"explicit": explicit,
"hidden": hidden,
}
def test_summary_uses_only_visible_tracks() -> None:
tracks = [
make_track("Compile Me Maybe", 181),
make_track("Draft Demo", 92, hidden=True),
make_track("Cache Me Outside", 228),
]
summary = summarize_playlist(tracks)
assert summary["track_count"] == 2
assert summary["labels"] == [
"Compile Me Maybe — The Testers",
"Cache Me Outside — The Testers",
]
def test_explicit_visible_track_is_labeled() -> None:
tracks = [
make_track(
"Null Pointer Mood",
203,
artist="The Exceptions",
explicit=True,
),
]
summary = summarize_playlist(tracks)
assert summary["labels"] == [
"Null Pointer Mood — The Exceptions (explicit)",
]
def test_minutes_total_counts_only_visible_seconds() -> None:
tracks = [
make_track("One Minute Opener", 60),
make_track("Hidden Long Jam", 600, hidden=True),
make_track("Two Minute Closer", 120),
]
summary = summarize_playlist(tracks)
assert math.isclose(summary["minutes"], 3.0)
Step 1 — Knowledge Check
Min. score: 80%
1. Before tracing playlist_summary.py, which evidence gives the strongest first hypothesis about the module’s purpose?
A purpose hypothesis should start from specification-level beacons: test names, public function names, and behavior words. Here they point to summarizing a public playlist while excluding hidden tracks.
2. The question is: ‘Are hidden tracks included in the final summary?’ Which region should you inspect first?
visible_tracks() is the shortest path from the question to evidence. You only need to trace hidden=True through that filter and confirm summarize_playlist() uses the filtered list.
3. Which summary is strongest after reading this module?
A good comprehension summary climbs abstraction levels: user-visible purpose first, then the major behaviors that support it.
4. Which are reliable beacons in this small Python example? (select all that apply)
The strongest beacons are the ones that connect names to behavior: tests, helper names, and role-revealing variables.
5. Which explanation best follows the Purpose / Mechanism / Evidence / Limit frame?
EiPE explanations combine purpose, mechanism, evidence, and a boundary on the claim, so the reader avoids both line narration and overconfidence.
Python Reading Sprint
Why this matters
Speed improves when you practice attention control, not when you rush. This timed round asks you to read just enough Python to answer targeted questions. The goal is not to finish perfectly; let’s see how far you can make it.
🎯 You will learn to
- Apply hypothesis-driven reading under a realistic time box
- Choose which details to ignore when the question is narrow
- Verify a Python comprehension hypothesis with one focused trace
Reading Goal
You have 7 minutes. Read event_cards.py and answer the quiz. Use this plan:
- Read function names and the sample data keys.
- Predict what
build_event_cards()returns. - Find the filtering step.
- Trace only one event through the relevant branch if needed.
- Vary the input mentally: change
todayortagand predict what behavior should change.
Use reading-notes.md to jot the evidence you find. The core target is
the first three quiz questions. The full-event trace is a stretch target
if you still have time.
Do not edit the code. This is a reading sprint, not an implementation task.
# Python Reading Sprint Notes
Hypothesis:
Top 3 beacons:
1.
2.
3.
What I can ignore for this question:
Smallest trace:
Final EiPE summary:
from typing import TypedDict
class Event(TypedDict):
title: str
day: int
capacity: int
registered: int
cancelled: bool
tags: list[str]
class EventCard(TypedDict):
title: str
spots: int
status: str
EVENTS: list[Event] = [
{"title": "Debugging Jam", "day": 14, "capacity": 30, "registered": 27, "cancelled": False, "tags": ["python", "tools"]},
{"title": "React Snack Lab", "day": 17, "capacity": 24, "registered": 12, "cancelled": False, "tags": ["react", "frontend"]},
{"title": "Legacy Code Karaoke", "day": 10, "capacity": 20, "registered": 20, "cancelled": False, "tags": ["reading"]},
{"title": "Node Night Market", "day": 18, "capacity": 18, "registered": 18, "cancelled": False, "tags": ["node", "backend"]},
{"title": "Cancelled CSS Cafe", "day": 20, "capacity": 12, "registered": 4, "cancelled": True, "tags": ["frontend"]},
]
def upcoming_events(events: list[Event], today: int) -> list[Event]:
return [
event
for event in events
if event["day"] >= today and not event["cancelled"]
]
def seats_left(event: Event) -> int:
return max(event["capacity"] - event["registered"], 0)
def matches_tag(event: Event, tag: str) -> bool:
return tag == "all" or tag in event["tags"]
def build_event_cards(
events: list[Event],
today: int,
tag: str = "all",
) -> list[EventCard]:
cards: list[EventCard] = []
for event in upcoming_events(events, today):
if matches_tag(event, tag):
spots = seats_left(event)
cards.append({
"title": event["title"],
"spots": spots,
"status": "full" if spots == 0 else "open",
})
return cards
if __name__ == "__main__":
print(build_event_cards(EVENTS, today=14, tag="frontend"))
Step 2 — Knowledge Check
Min. score: 80%
1. What is the best purpose hypothesis for build_event_cards()?
The helper names form a chain: upcoming events, tag matching, seats left, then card construction.
2. For today=14 and tag="frontend", which answer gives the result and the evidence?
React Snack Lab is upcoming, not cancelled, and has the requested tag.
3. Which detail can you safely ignore when answering whether cancelled events appear?
Attention control includes deciding what not to read. Seat math does not determine whether cancelled events enter the result.
4. Which small trace best verifies the hypothesis that full events are still included?
Node Night Market is full and not cancelled. Tracing it through the relevant helpers tests exactly the hypothesis.
5. Which note best shows useful vary-the-input reasoning?
Varying one input at a time helps verify which branch or helper actually controls the behavior.
Beacon Categories
Why this matters
Beacons are the cues that let you read code faster without becoming careless. In React, many beacons are framework-shaped: useState suggests local component memory, props suggest parent-to-child data flow, and .filter(...).map(...) often means “derive a visible list from data.” The skill is learning which cues deserve trust.
🎯 You will learn to
- Classify lexical, structural, framework, and test/specification beacons
- Use React beacons to predict component responsibilities
- Decide when a beacon is too weak to trust without verification
Four Beacon Types
| Beacon type | What it looks like | What it helps you infer |
|---|---|---|
| Lexical | SnackCard, visibleSnacks, onVote |
Domain responsibility and data flow |
| Structural | .filter(...).map(...), accumulator loops, guard clauses |
A familiar programming plan |
| Framework | React.useState, props, onClick, key |
React-specific component behavior |
| Specification | Tests, assertions, user stories, acceptance criteria | Expected behavior before implementation |
A beacon can be weak. A CSS class such as snack-grid is useful
evidence about layout, but it is poor evidence for behavior such as
persistence, filtering, or state ownership.
Predict Before Reading
Look at the React files. Before reading every JSX element, predict:
- Which component owns the voting state?
- Which component only displays one snack?
- Which expression probably decides which snacks are visible?
Then inspect only the regions that can prove or disprove those predictions.
.snack-shell {
max-width: 54rem;
margin: 0 auto;
padding: 1.5rem;
}
.snack-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(14rem, 1fr));
gap: 1rem;
}
const SNACKS = [
{ id: 1, name: "Mango Mochi", category: "sweet", votes: 9 },
{ id: 2, name: "Wasabi Peas", category: "savory", votes: 6 },
{ id: 3, name: "Chocolate Pretzels", category: "sweet", votes: 12 },
{ id: 4, name: "Seaweed Chips", category: "savory", votes: 4 },
];
function SnackCard({ snack, onVote }) {
return (
<article className="border rounded p-3">
<h2 className="h5">{snack.name}</h2>
<p>Category: {snack.category}</p>
<p>Votes: {snack.votes}</p>
<button type="button" onClick={() => onVote(snack.id)}>
Vote
</button>
</article>
);
}
function App() {
const [category, setCategory] = React.useState("all");
const [snacks, setSnacks] = React.useState(SNACKS);
function handleVote(id) {
setSnacks(currentSnacks => currentSnacks.map(snack =>
snack.id === id ? { ...snack, votes: snack.votes + 1 } : snack
));
}
const visibleSnacks = snacks.filter(snack =>
category === "all" || snack.category === category
);
return (
<main className="snack-shell">
<h1>Snack Vote</h1>
<label>
Category
<select value={category} onChange={event => setCategory(event.target.value)}>
<option value="all">All</option>
<option value="sweet">Sweet</option>
<option value="savory">Savory</option>
</select>
</label>
<section className="snack-grid" aria-label="Snack choices">
{visibleSnacks.map(snack => (
<SnackCard key={snack.id} snack={snack} onVote={handleVote} />
))}
</section>
</main>
);
}
const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(<App />);
Step 3 — Knowledge Check
Min. score: 80%
1. Which beacon most strongly tells you that App owns state that can change over time?
useState is a React framework beacon: it marks component-owned memory and a setter that can trigger a re-render.
2. The expression snacks.filter(...).map(...) is mainly which kind of beacon?
The structure compresses many details into a plan: choose the relevant data, then transform each item into JSX.
3. A reader wants to know what happens when the Vote button is clicked. Which path should they inspect?
The interaction crosses a component boundary: child button → callback prop → parent state update.
4. Which beacons are strong enough to support a first-pass prediction? (select all that apply)
A useful beacon has a tight relationship to behavior. Presentation class names are usually weaker than state, props, and list-rendering patterns.
5. Which cue is the weakest evidence for how votes change?
Weak-beacon diagnosis keeps fast reading from becoming careless guessing.
React Reading Sprint
Why this matters
React code can look visually busy because JSX mixes data, structure, and event wiring. Beacon reading lets you find the small number of expressions that control the behavior you care about. This sprint is a little larger than the Python one, so use the routine and let’s see how far you can make it.
🎯 You will learn to
- Apply React beacon reading to props, state, filters, and conditional rendering
- Explain a component’s purpose without tracing every JSX tag
- Decide which component owns a behavior
Reading Goal
You have 8 minutes. Your target is not “understand every line.” Your target is:
- Who owns the selected topic?
- Which tasks are visible?
- When does the completion banner appear?
- Which component is display-only?
Use reading-notes.md to record your hypothesis, strongest beacons, and
smallest useful trace. As a transfer check, notice what this React code
shares with the Python sprint: both derive a visible list, then shape
that list for display.
After this step, wait two or three days before starting the advanced tutorial. That delay is not wasted time; it is how spacing turns today’s code-reading routine into something you can retrieve later.
# React Reading Sprint Notes
Hypothesis:
Top 3 beacons:
1.
2.
3.
What I can ignore for this question:
Smallest trace:
Final EiPE summary:
.queue-shell {
max-width: 58rem;
margin: 0 auto;
padding: 1.5rem;
}
.task-card {
border: 1px solid #c9d3df;
border-radius: 6px;
padding: 1rem;
margin-block: 0.75rem;
}
const TASKS = [
{ id: 1, title: "Read route tests", topic: "node", done: true },
{ id: 2, title: "Trace prop callback", topic: "react", done: false },
{ id: 3, title: "Label accumulator role", topic: "python", done: true },
{ id: 4, title: "Map route to helper", topic: "node", done: false },
];
function TopicFilter({ topic, onTopicChange }) {
return (
<label>
Topic
<select value={topic} onChange={event => onTopicChange(event.target.value)}>
<option value="all">All</option>
<option value="python">Python</option>
<option value="react">React</option>
<option value="node">Node</option>
</select>
</label>
);
}
function TaskCard({ task }) {
return (
<article className="task-card">
<h2 className="h5">{task.title}</h2>
<p>Topic: {task.topic}</p>
{task.done ? <strong>Done</strong> : <span>Still practicing</span>}
</article>
);
}
function App() {
const [topic, setTopic] = React.useState("all");
const visibleTasks = TASKS.filter(task =>
topic === "all" || task.topic === topic
);
const allVisibleDone = visibleTasks.length > 0 &&
visibleTasks.every(task => task.done);
return (
<main className="queue-shell">
<h1>Study Queue</h1>
<TopicFilter topic={topic} onTopicChange={setTopic} />
{allVisibleDone && <p role="status">Everything visible is done.</p>}
<section aria-label="Visible study tasks">
{visibleTasks.map(task => (
<TaskCard key={task.id} task={task} />
))}
</section>
</main>
);
}
const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(<App />);
Step 4 — Knowledge Check
Min. score: 80%1. Which component owns the selected topic state?
App owns state and passes it down. The child component sends changes upward by calling the callback prop.
2. If the selected topic is react, which task appears?
visibleTasks keeps tasks where task.topic === topic, so the React task remains.
3. When does the Everything visible is done. status appear?
The condition combines two checks: there must be visible tasks, and all of them must be done.
4. Which statements are good evidence-based summaries of this React code? (select all that apply)
A strong React summary names state ownership, callback direction, and derived rendering.
5. What plan is shared by the Python event-card sprint and this React study-queue sprint?
Transfer improves when you name the shared code plan across languages: select relevant data, then shape it for the consumer.
Variable Roles and Plans
Why this matters
Beacons are easier to trust when you know the role each value plays. Novices often trace variable values forever; stronger readers ask whether a variable is a stepper, accumulator, candidate, flag, or organizer. That role label compresses several lines into a plan you can verify selectively.
🎯 You will learn to
- Classify variables by role before tracing every update
- Recognize aggregation and max-tracking plans from variable roles
- Verify one role hypothesis with a small input trace
Variable Roles Are Beacons
Use this table while reading badge_recommender.py.
| Role | What it usually does | Typical beacon |
|---|---|---|
| Stepper | Moves through a collection | entry, track, item inside a loop |
| Accumulator / gatherer | Collects totals or output | total, badges, topic_minutes |
| Candidate / best-so-far | Remembers the current winner | best_topic, best_minutes |
| Flag | Records whether a condition has happened | is_ready, has_warning |
| Organizer | Groups data by key | dictionary keyed by topic, id, or date |
Worked Reading Example
If the question is:
“How does the code know which topic is strongest?”
Do not trace every entry first. Use the role beacons:
| Move | Evidence | Hypothesis |
|---|---|---|
| Orient | strongest_topic(topic_minutes) |
This helper probably chooses one topic |
| Beacon-hunt | best_topic, best_minutes |
This looks like a best-so-far plan |
| Descend | The if minutes > best_minutes branch |
The branch updates the current winner |
| Verify | Trace {"python": 35, "react": 42} |
React should replace Python as best |
Your Turn
Read the public function recommend_badges() first, then inspect the helpers. Write a role table in your notes:
- Which value organizes minutes by topic?
- Which values hold the current candidate?
- Which value gathers the final user-facing output?
- Which input path would you trace to verify that zero-minute entries are ignored?
You do not need to edit the code.
from typing import TypedDict
class ActivityEntry(TypedDict):
topic: str
minutes: int
TopicMinutes = dict[str, int]
ACTIVITY_LOG: list[ActivityEntry] = [
{"topic": "python", "minutes": 18},
{"topic": "react", "minutes": 12},
{"topic": "python", "minutes": 22},
{"topic": "node", "minutes": 35},
{"topic": "react", "minutes": 0},
{"topic": "python", "minutes": 15},
]
def summarize_minutes(entries: list[ActivityEntry]) -> TopicMinutes:
topic_minutes: TopicMinutes = {}
for entry in entries:
if entry["minutes"] <= 0:
continue
topic = entry["topic"]
topic_minutes[topic] = topic_minutes.get(topic, 0) + entry["minutes"]
return topic_minutes
def strongest_topic(topic_minutes: TopicMinutes) -> tuple[str | None, int]:
best_topic: str | None = None
best_minutes = 0
for topic, minutes in topic_minutes.items():
if minutes > best_minutes:
best_topic = topic
best_minutes = minutes
return best_topic, best_minutes
def recommend_badges(
entries: list[ActivityEntry],
minimum_minutes: int = 30,
) -> list[str]:
topic_minutes = summarize_minutes(entries)
topic, minutes = strongest_topic(topic_minutes)
badges: list[str] = []
for name, total in sorted(topic_minutes.items()):
if total >= minimum_minutes:
badges.append(f"{name}: {total} min")
if topic and minutes >= minimum_minutes * 2:
badges.append(f"focus: {topic}")
return badges
if __name__ == "__main__":
print(recommend_badges(ACTIVITY_LOG))
Step 5 — Knowledge Check
Min. score: 80%
1. What role does topic_minutes play in summarize_minutes()?
The dictionary key is the topic, and the value accumulates minutes for that topic.
2. Which variables are the strongest beacons for the best-so-far plan?
A best-so-far plan usually keeps a current candidate and the score that justifies it.
3. What is the best purpose-level summary of recommend_badges()?
The purpose summary names the whole behavior and the major plans: aggregate, threshold-filter, and best-so-far.
4. Which trace best verifies that zero-minute entries are ignored?
A targeted trace follows exactly the branch that can confirm or refute the role hypothesis.
5. Which statements correctly connect variable roles to programming plans? (select all that apply)
Variable roles let readers name the plan before they trace all values.
Python Plan Transfer Sprint
Why this matters
The final basic sprint asks you to transfer the same reading routine to a new Python example with a few more moving parts. This is where fluency starts to form: you see a new surface story, but the deeper plans are familiar. Use the beacons, keep your trace narrow, and let’s see how far you can make it.
🎯 You will learn to
- Recognize familiar plans in a larger Python function
- Separate central behavior from nearby helper detail
- Use vary-the-input reasoning to test a comprehension hypothesis
Reading Goal
You have 10 minutes. Read habit_report.py and answer the quiz.
Focus on these questions:
- What does
build_habit_report()return? - Which helper removes skipped or zero-minute check-ins?
- Which helper groups minutes by skill?
- Which helper computes a streak?
- What can you ignore if the question is only about filtering?
Use reading-notes.md to write a purpose hypothesis, three beacons, and one smallest useful trace. The stretch goal is the streak question.
# Python Plan Transfer Sprint Notes
Purpose hypothesis:
Top 3 beacons:
1.
2.
3.
What I can ignore for this question:
Smallest trace:
Final EiPE summary:
from typing import TypedDict
class Checkin(TypedDict):
day: int
skill: str
minutes: int
skipped: bool
class HabitReport(TypedDict):
skills: list[str]
total_minutes: int
totals: dict[str, int]
longest_streak: int
CHECKINS: list[Checkin] = [
{"day": 1, "skill": "python", "minutes": 25, "skipped": False},
{"day": 2, "skill": "python", "minutes": 20, "skipped": False},
{"day": 3, "skill": "react", "minutes": 15, "skipped": False},
{"day": 4, "skill": "python", "minutes": 0, "skipped": True},
{"day": 5, "skill": "node", "minutes": 30, "skipped": False},
{"day": 6, "skill": "python", "minutes": 18, "skipped": False},
]
def useful_checkins(checkins: list[Checkin]) -> list[Checkin]:
return [
checkin
for checkin in checkins
if not checkin["skipped"] and checkin["minutes"] > 0
]
def minutes_by_skill(checkins: list[Checkin]) -> dict[str, int]:
totals: dict[str, int] = {}
for checkin in checkins:
skill = checkin["skill"]
totals[skill] = totals.get(skill, 0) + checkin["minutes"]
return totals
def longest_streak(checkins: list[Checkin], skill: str) -> int:
days = sorted(
checkin["day"]
for checkin in checkins
if checkin["skill"] == skill
)
longest = 0
current = 0
previous_day = None
for day in days:
if previous_day is None or day == previous_day + 1:
current += 1
else:
current = 1
longest = max(longest, current)
previous_day = day
return longest
def build_habit_report(
checkins: list[Checkin],
skill: str = "all",
) -> HabitReport:
useful = useful_checkins(checkins)
if skill != "all":
useful = [checkin for checkin in useful if checkin["skill"] == skill]
totals = minutes_by_skill(useful)
total_minutes = sum(totals.values())
streaks = {name: longest_streak(useful, name) for name in totals}
return {
"skills": sorted(totals),
"total_minutes": total_minutes,
"totals": totals,
"longest_streak": max(streaks.values(), default=0),
}
if __name__ == "__main__":
print(build_habit_report(CHECKINS, skill="python"))
Step 6 — Knowledge Check
Min. score: 80%
1. What is the strongest purpose hypothesis for build_habit_report()?
The public function name and return keys point to a report-building purpose.
2. Which helper is central for deciding whether skipped check-ins count?
useful_checkins() contains the skipped/minutes predicate, so it is the shortest path for the filtering question.
3. If skill="python", which check-ins can affect total_minutes?
Vary-the-input reasoning follows the filters in order: useful first, skill second, totals third.
4. Which detail can you ignore if the only question is whether skipped check-ins contribute to totals?
Attention control means ignoring real code when it is not relevant to the current hypothesis.
5. Which plan labels fit this Python example? (select all that apply)
Interleaved plan recognition helps transfer: the same code can contain filtering, aggregation, and best-so-far tracking.