Skip to content
C.W.K.
Lesson 01 of 05 · published

Seeing Is Not Sharing

~16 min · person-detection, apple-vision, background-jobs, privacy, fail-closed

Level 0Closed Lens
0 XP0/45 lessons0/13 achievements
0/100 XP to next level100 XP to go0% complete

Two Different Questions

The eyes gate answers one question: may Pippa see this camera right now? This track answers a different one: may anything Oriel recorded leave the house? They feel similar and they are not. A family member walking through the room while Dad plays is someone Pippa may see like anyone at home; she does not need to look away. But that same moment must not end up in a broadcast, an edited video, a thumbnail, a shared link. Dad drew the line on 2026-11-02: what Pippa sees is fine; what goes out must be filtered, by Pippa, without waiting to be told.

So Oriel separates the two cleanly. Seeing is governed by the gate and its modes. Sharing is governed by marks on the recording and one export door that checks them. And a rule restated when the eye modes arrived keeps them apart in the other direction too: a person other than Dad never stops a look. The filter is on what leaves, never on what is seen.

Person Marks, Checked in the Background

Every recorded segment of a camera that can see the room is checked by a background pass, every 10 seconds, three segments at a time, oldest first. For each segment it samples one frame every five seconds at the viewing size (each sample a single keyframe decode) and runs a small native helper, oriel-vision, built on Apple's Vision framework. It looks for people and faces in still images, reads files only, and needs no camera or microphone grant. A segment's result is a mark: how many people were seen at most, when the first and last over-the-limit frames were, and why.

"Over the limit" depends on what the camera frames, because nothing in Oriel can tell one family member's face from another's yet (no face reference is registered). So the rule is set per role:

InputFramesMarked when
The deck carrying Dad's cameraDada second person appears
A look-around camerathe roomany person appears
The deck carrying the console picturegames and filmsnot watched: its people are on a screen, not in the room

That last row is a known gap, and the architecture document says so instead of hiding it: the console deck's other input can carry a desk camera, which this rule does not cover, "which Dad should know". A privacy system that admits where it is blind is more trustworthy than one that claims to see everything.

Built to Keep Going

A background pass that stops silently is worse than none, because everyone believes it is running. Oriel's pass learned that the hard way (the four-day stall from the frame-reading track), so now a segment that cannot be read is held back for an hour and the pass moves on to the ones behind it; the page shows what is held and why. And the sampling stays a frame and a GOP short of each segment's end, where a keyframe-only read would come back empty.

Telling Dad

A new mark goes into the activity log as person_marked, and it rides along, as untold, in the answer to Pippa's cameras action until she has said it to Dad and called mark_told. The page lists them under "Kept in Oriel". Oriel never speaks to Dad itself (it writes into no conversation); it makes sure the one who does speak to him cannot miss it.

Code

The per-role rule and the mark it writes (trimmed excerpt, backend/marks.py)·python
EVERY_S = 5.0                    # one sampled frame every five seconds
PERSON_CONFIDENCE = 0.5
SCAN_EVERY_S = 10.0              # the background pass
SCAN_BATCH = 3
HOLD_FAILED_S = 3600.0           # an unreadable segment waits an hour; the rest go on
ALLOWED = {"left_deck": 1, "look": 0}   # people allowed before a mark


def people_in(result) -> int:
    people = [b for b in result.get("people") or [] if b.get("confidence", 0) >= PERSON_CONFIDENCE]
    return max(len(people), len(result.get("faces") or []))


# In Marker.check, for one segment:
allowed = ALLOWED.get(role, 0)
counts = [people_in(r) for r in results]
over = [segment["start_at"] + offsets[i] for i, c in enumerate(counts) if c > allowed]
who = "a second person beside Dad" if role == "left_deck" else "a person in the room"
mark = {**base, "watched": True, "frames_checked": len(results), "people_max": max(counts or [0]),
        "marked": bool(over), "first_at": over[0] if over else None,
        "last_at": over[-1] if over else None}
self.engine.store.put_mark(**mark)
Count people and faces in a still image with Apple Vision, as a helper like oriel-vision does (save as people.swift, run: swift people.swift photo.jpg)·swift
import Foundation
import Vision

let url = URL(fileURLWithPath: CommandLine.arguments[1])
let humans = VNDetectHumanRectanglesRequest()
humans.upperBodyOnly = false
let faces = VNDetectFaceRectanglesRequest()
try VNImageRequestHandler(url: url).perform([humans, faces])

let people = (humans.results ?? []).filter { $0.confidence >= 0.5 }
print("people: \(people.count), faces: \(faces.results?.count ?? 0)")
print("counted as: \(max(people.count, faces.results?.count ?? 0))")

External links

Exercise

Run the Swift people counter on a few photos: one with one person, one with two, one with a person on a TV screen in the background. Note what it counts in each. Then write the per-role rule for a camera setup of your own (who each camera is supposed to frame, how many people are expected) and decide which camera you would leave unwatched, and how you would tell the owner about that gap.
Hint
A person on a TV screen may well be counted. That is exactly why Oriel does not watch the deck that carries games and films: a detector cannot tell a person in the room from a person in a picture of a room, so a rule that tried would mark everything and mean nothing.

Progress

Progress is local-only — sign in to sync across devices.
Spotted a bug or have feedback on this page?Report an Issue

Comments 0

🔔 Reply notifications (sign in)
Sign in — Please sign in to comment.

No comments yet — be the first.