Good place to stop if you're short on time — step 3 picks up here.
Lesson idea Tap to fold
Name the audit trail before calculating a metric.
Show the answer
Raw rows, invalid rows, duplicates removed, clean rows, and the rule for every exclusion.
Build a defensible audit, not a polished-looking number
The four guided tasks trace, rebuild, fill and repair a small pandas audit. Their inputs are valid JSON object lines with typed nonempty fields when present; they demonstrate first-global-ID retention, acceptance and reference agreement, not a complete ingestion boundary. Rebuild returns an empty DataFrame with item_id/label columns for empty input. The independent final project extends the policy to malformed JSON, invalid types, blank lines and explicit issue evidence.
Use a validation → retention → aggregation → report pipeline. Validate before reserving a cleaned global ID, keep first valid occurrences, count each exclusion exactly once and retain source line numbers. Acceptance counts pass labels; agreement counts label/gold equality, including fail/fail. Overall rates use retained rows, not the average of model percentages. None records an absent denominator instead of an invented zero.
The final brief specifies build_audit, save_audit and test_audit. Return reusable data, save the actual data as JSON and write tests that catch empty, malformed and duplicate mistakes. Allow 95 minutes in two sessions: the guided tasks take about 50 minutes and the independent project about 45, plus the separate quiz. Explanations and portfolio readiness are self-reviewed; software checks alone do not certify learning. Use the Studio course map for the next project path.
# Keep the retained-row denominator, not model means.
groups = [
{"rows": 1, "matches": 1},
{"rows": 3, "matches": 1},
]
rows = sum(group["rows"] for group in groups)
matches = sum(group["matches"] for group in groups)
rate = matches / rows if rows else None
print("Retained agreement:", rate)
print("No observations:", None)
assert rows == 4
assert matches == 2
Two matches among four retained rows means 0.5 agreement; averaging the group percentages would answer a different question.
Explain exclusions, policy and sample limits before interpreting a rate. Preserve the downloaded report and your code; local browser storage is not a cloud backup.
Predict, explain, then test
These three comparisons are self-reviewed, not scored. Coding checks run new inputs; the section quiz records separate knowledge evidence.
Account for evidence
Which counts must add up to physical input lines?
Compare your answer · self-reviewed
Blank + rejected + duplicates + kept. A line belongs to one category, with one-based issue evidence for exclusions other than blanks.
Validate first
An invalid row appears before a valid row with the same ID. Which may reserve the ID?
Compare your answer · self-reviewed
Only the first valid cleaned global ID reserves identity. Invalid earlier rows must not suppress valid evidence.
Read a rate
One model has 1/1 matches and another 1/3. What is overall agreement?
Compare your answer · self-reviewed
2/4 = 0.5 over retained rows, not the unweighted mean of the model percentages.
Independent final audit: evidence and a real report
Follow this independent policy rather than copying the narrower guided demonstration:
- Write build_audit(raw) for a JSONL string; reject non-string callers with TypeError. Use raw.splitlines(): a trailing line terminator does not add a phantom line. Start fresh on each call.
- Classify every line in order: whitespace-only is blank; malformed JSON is rejected with reason json; JSON that is not a dictionary is rejected with reason object. A dictionary is rejected with reason fields unless item_id and model are nonempty strings after stripping outer whitespace, and label/gold are exact string pass or fail values. Allow extra fields; do not coerce types.
- After validation, retain the first valid cleaned global item_id, regardless of model. Later valid occurrences are duplicates with reason duplicate. An invalid earlier occurrence does not reserve an ID. Keep line numbers one-based and issue entries as {line: number, reason: text}, in source order. Blank lines have no issue entry.
- Return exactly lines, blank, rejected, duplicates, kept, acceptance, agreement, issues and models. Count exclusions separately so lines = blank + rejected + duplicates + kept. models maps each cleaned model to rows, accepted, matches, acceptance, agreement and disagreements: an input-order list of retained item IDs where label differs from gold.
- Count pass as accepted and equality of label/gold as a match, including fail/fail. Overall acceptance/agreement use all retained rows. Per-model rates use that model’s retained rows. Round defined fractions to four decimals only after calculating. Return None for overall rates when kept is zero; models is then empty. Counts are native integers, not booleans.
- Write save_audit(raw), which calls build_audit, writes its actual returned report as UTF-8 JSON plus a final newline to project-report.txt, and returns that same data. Do not write a fixed sample or a Python repr. The browser collects the sample file before its checks rerun new cases; use the explicit download button to keep it.
- Write test_audit() containing at least three real assertions: empty input has zero kept rows, malformed JSON is counted as rejected, and repeated valid global IDs are counted as duplicates. Call it before saving the supplied sample. The checker also tests whether these assertions detect those rules when deliberately broken.
- Explain one exclusion, the global-ID retention policy and the denominator behind a rate. These explanations are self-reviewed, not automatically scored. The report describes this retained sample and reference; it does not prove general model quality or certification. Allow 50 minutes for the four guided tasks and 45 for this independent task, in two sessions; quiz time is separate.
Select the final project in the controls. The quiz practical link selects it without running code or awarding evidence. Review JSON, validation, writing and verifying report files and meaningful tests.
Read the unfinished starter without running Python
# Build and test a new audit policy independently.
import json
# Return counts, issue evidence and retained group rates.
def build_audit(raw):
return {}
# Write the returned report, not a fixed sample.
def save_audit(raw):
return build_audit(raw)
# Replace the placeholder with three meaningful checks.
def test_audit():
assert True
# Keep the supplied six physical input lines.
raw = (
'{"item_id":"a1","model":"Canal",'
'"label":"pass","gold":"pass"}\n'
'{"item_id":"a2","model":"Canal",'
'"label":"fail","gold":"pass"}\n'
'{"item_id":"a1","model":"Museum",'
'"label":"fail","gold":"fail"}\n'
'broken\n{}\n '
)
test_audit()
report = save_audit(raw)
print("Kept:", report["kept"])
print("Rejected:", report["rejected"])
print("Duplicates:", report["duplicates"])
print("Report: project-report.txt")
The sample retains two Canal rows, with acceptance/agreement 0.5 and disagreement a2. It excludes one duplicate on line 3, malformed JSON on line 4 and invalid fields on line 5, plus a blank sixth line. Expected output is Kept: 2, Rejected: 2, Duplicates: 1 and Report: project-report.txt on separate lines. Download the actual UTF-8 report explicitly; a passing quiz does not pass this project.
Next: Four Studio readiness tasks and targeted refreshers · Python Studio course map · All training and shared tutor login. Do not treat a software pass or a self-review tick as certification.
Choose an exercise to load its prompt.
Loading exercises…
Noted on your route map, with the step you were on. Nothing is lost by parking it — the next review day will bring this idea back, and the flag tells the course where to slow down.
Section 8 checkpoint
Answer five questions, inspect explanations and use the targeted refreshers. The final audit and its real report are a separate practical task. Neither requires tutor login.
The tutor mounts here when JavaScript is available. The lesson above stays readable without it.