Leg 5 project: the device report
Why it matters This is the full job, start to finish: a capture from a home with a phone and a smart TV, and a short report that says, for each device, who it talks to, what IDs and kinds of data it sends, and whether the two devices can be linked to the same person. It is exactly the report you would want about your own home.
The capture
hidden_capture() gives you a capture with two devices on one home network:
from watched.leg5b_apps import hidden_capture, SDK_OWNERS
cap = hidden_capture()
print(cap["first_party"]) # {'phone': 'StepBee', 'tv': 'ScreenMaker'}
print(len(cap["entries"]))
print(cap["entries"][0]["device"]) # 'phone' or 'tv'
first_party says which company made each device's software (the phone app's maker, and the TV's maker). Every entry has the same shape as before, plus "device". The grader also runs your code on other hidden captures (hidden_capture(seed) with seeds you do not see), so do not hard-code anything about this one.
The report
Your report is a dict with two keys. "devices" maps each device name in first_party to a dict with:
| Key | Value |
|---|---|
"destinations" | sorted list of every owner that device contacted (use your owner_of; include the device's own maker and "Unknown" if they appear) |
"identifiers" | sorted list, no repeats, of identifier field names sent with a real value |
"zeroed_ad_id" | True if any field in AD_ID_NAMES was sent with the value ZERO_AD_ID |
"location" | True if any field of kind location was sent |
"acr" | True if any field of kind viewing was sent |
"score" | the sharing score of that device's entries, with the device's first_party owner as the app owner |
"linked_ids" is a sorted list of identifier values (real ones only) that were sent by more than one device. If the same value leaves both the phone and the TV, anyone who receives both can tell they belong to one household, or one person.
Cross-device linking: recognising that two devices belong to the same person, usually because both send the same account ID or hashed email. It is how a TV advert and a phone purchase get joined into one profile.
Plan before you code
- Copy in
owner_of,sharing_graphandsharing_scorefrom the last exercise. - For each device, filter its entries:
[e for e in cap["entries"] if e["device"] == device]. - Walk every field once, using
fields_ofandDATA_KINDS, setting the flags and collecting identifier names. While you are there, record which devices sent each real identifier value, in a dict value -> set of devices. - Build the graph for the device's entries; its keys, sorted, are the destinations, and it gives you the score.
- After all devices, keep the values whose set has more than one device.
Finally, the "submit" step: turn the report into JSON text with json.dumps(report, sort_keys=True). JSON is the plain-text format almost every tool can read, which is why reports and APIs use it.
Reading your own result
When you print your report, notice three things. Does the phone show zeroed_ad_id and still send other identifiers? Does the TV send viewing data, and to whom? And is there a linked value? On this capture there is: the hashed email. One sign-in on each device is enough to join them.
The defence
Every line of the report suggests a fix: switch off ACR on the TV, say no to tracking on the phone, sign in to the TV only if you need to (or with a different email), and limit location to "while using". Run the report again on a capture after those changes and the score drops; that before-and-after is the evidence.
In other languages
JavaScript: the linking step, with a Map of Sets.
const seen = new Map();
for (const e of cap.entries) {
for (const [name, value] of fieldsOf(e)) {
if (DATA_KINDS[name] === "identifier" && value !== ZERO_AD_ID && value.trim()) {
if (!seen.has(value)) seen.set(value, new Set());
seen.get(value).add(e.device);
}
}
}
const linked = [...seen].filter(([, d]) => d.size > 1).map(([v]) => v).sort();
const reportJson = JSON.stringify(report);
PHP: json_encode($report) does the submit step.
Recap
- A device report lists, per device, the owners contacted, identifiers sent, location and viewing flags, and a score.
- The same real ID value leaving two devices links them to one person.
- JSON is the plain-text format for handing a report to other tools.
- Re-running the report after changing settings gives you evidence that the settings worked.
Write device_report(capture, owners) that returns the report described above: a dict with "devices" (one entry per device in capture["first_party"], each with destinations, identifiers, zeroed_ad_id, location, acr and score) and "linked_ids". You will also need owner_of, sharing_graph and sharing_score from the last exercise; define them in this program. Use fields_of, DATA_KINDS, AD_ID_NAMES and ZERO_AD_ID from the practice world.
Then set report = device_report(hidden_capture(), SDK_OWNERS), set report_json = json.dumps(report, sort_keys=True), and print report_json.
This lesson is locked
Lessons open one at a time. Finish the previous lesson to unlock this one.