Complete Walkthrough: Plan, Build and Review a Real Parsing Task
Task: A platform inventory service returns JSON records with
service,regionandstatus. Report the number of unhealthy records by region and service, sorted by descending count. The input may contain malformed records, and the caller must be able to tell whether results are complete.
We will work through the whole Plan–Build–Review (PBR) cycle without using any vendor-specific product or tool. The goal is to demonstrate a repeatable engineering method that works with or without an agent.
Stage 1: Understand and plan
Clarify the input and behavior:
- The input is a JSON string containing a list of event objects.
- Valid records require non-empty string
serviceandregion, and status fromhealthy,degraded,unhealthy. - Count only
degradedandunhealthy; they are equally counted as unhealthy events for this exercise. - Each input record is one observation. There is no event ID, so duplicate records are counted separately.
- Invalid input should fail the entire operation rather than return partial output.
- Output is a list of dictionaries with region, service and count, sorted by count descending, then region and service ascending.
An alternative requirement might ask for unique services or latest status per host. That requires a stable identity and perhaps timestamps; do not quietly invent those semantics.
Minimal plan
- Parse JSON with the standard library.
- Require a list, and validate each object and required field.
- Accumulate
(region, service)counts in a dictionary or Counter. - Sort groups by
(-count, region, service). - Return a list of stable schema dictionaries.
- Execute tests for empty, mixed states, ties, malformed JSON and invalid types.
Time: O(n + k log k) for n records and k distinct unhealthy region/service groups. Space: O(n) for decoded input plus O(k) counters. If the source becomes a very large stream, replace the top-level JSON array with paginated records or NDJSON and process incrementally.
Stage 2: Build the function
import json
from collections import Counter
VALID_STATES = {"healthy", "degraded", "unhealthy"}
def unhealthy_summary(payload: str) -> list[dict]:
try:
rows = json.loads(payload)
except json.JSONDecodeError as exc:
raise ValueError("invalid JSON") from exc
if not isinstance(rows, list):
raise ValueError("expected a JSON list")
counts = Counter()
for index, row in enumerate(rows):
if not isinstance(row, dict):
raise ValueError(f"row {index} must be an object")
service = row.get("service")
region = row.get("region")
status = row.get("status")
if not isinstance(service, str) or not service.strip():
raise ValueError(f"row {index} has invalid service")
if not isinstance(region, str) or not region.strip():
raise ValueError(f"row {index} has invalid region")
if not isinstance(status, str) or status not in VALID_STATES:
raise ValueError(f"row {index} has invalid status")
if status != "healthy":
counts[(region.strip(), service.strip())] += 1
ranked = sorted(counts.items(), key=lambda pair: (-pair[1], pair[0]))
return [
{"region": region, "service": service, "count": count}
for (region, service), count in ranked
]Why this structure?
- The decoder deals with syntax, then the loop deals with schema.
- A Counter represents exactly the aggregation operation.
- A tuple key prevents collisions if different regions use the same service name.
- Sorting tuples gives deterministic region/service tie behavior.
- A single final output conversion makes the JSON structure easy to consume.
- No external dependencies, recursion, concurrency or network calls are required.
Stage 3: Test the result independently
sample = json.dumps([
{"service":"api","region":"a","status":"healthy"},
{"service":"api","region":"a","status":"unhealthy"},
{"service":"worker","region":"b","status":"degraded"},
{"service":"api","region":"a","status":"unhealthy"},
])
assert unhealthy_summary(sample) == [
{"region":"a", "service":"api", "count":2},
{"region":"b", "service":"worker", "count":1},
]
assert unhealthy_summary("[]") == []
# Input order does not change aggregate output.
original = [
{"service":"api", "region":"a", "status":"degraded"},
{"service":"worker", "region":"b", "status":"unhealthy"},
]
assert unhealthy_summary(json.dumps(original)) == unhealthy_summary(
json.dumps(list(reversed(original)))
)
for bad in ('not json', '{}', '[{"service":"api","region":"a"}]'):
try:
unhealthy_summary(bad)
except ValueError:
pass
else:
raise AssertionError("invalid input was incorrectly accepted")These tests verify only their specific assertions. Also test blank service/region, extra irrelevant fields, repeated healthy events and several region/service pairs tied for count.
Stage 4: Review the diff and challenge the semantics
A reviewer should ask:
- Are
degradedandunhealthyreally equivalent for reporting? - Is whitespace normalization desired? The implementation strips outer whitespace from names after validating they are not entirely blank.
- Do repeated records represent separate observations, or duplicate delivery? No stable ID was provided.
- Should malformed records reject the whole result or produce a partial report? Here we deliberately fail closed.
- Does JSON input size fit memory? This function decodes the entire array.
- Is status case-sensitive? Yes, by the explicit contract.
- Does sorted output remain stable under record shuffling? Yes, for this count-based task.
If the reviewer or user changes a requirement, update the contract and tests before editing the algorithm. For example, "count unique unhealthy services per region" is not the same as counting unhealthy observations.
Stage 5: Prompt sequence for an AI-assisted execution
Ask: "Restate the input/output schema and identify contradictions. Do not write implementation code."
Plan: "Recommend the simplest standard-library algorithm, complexity and six edge-case tests. Wait before editing."
Build: "Implement only unhealthy_summary with the approved behavior. Do not introduce extra dependencies or change the schema."
Review: "Independently find cases where this implementation violates the original contract. Supply minimal failing inputs. Report actual test evidence, not assumed correctness."
How to present your approach
"I clarify whether the requirement counts events or unique resources, and how invalid rows should behave. Then I validate the JSON shape, group by a tuple key in one pass and sort the small set of groups. I use hand-worked expected outputs for empty input, status variants, ties and malformed records. A coding assistant can suggest cases or write a small function, but I review the transformation and run independent checks myself."
Main principle: Planning, implementation and review should each produce different evidence. A test passing does not mean the initial requirement was understood correctly.