Ran behavision-setup in a fresh Linux container: Python 3.12, nothing
else, the release contents mounted read-only the way Program Files or a
shared drive would be. It failed, and then it failed differently, and
both failures would have been the client's first experience.
1. `pip install <folder>` makes setuptools write behavision.egg-info
INTO the folder. The folder is read-only wherever a release is
sensibly unzipped, so: "could not create 'behavision.egg-info':
Read-only file system". The release now ships a wheel - pure Python,
buildable anywhere, nothing to build on the shop PC, and pip never
touches the unzipped folder. Source stays as a fallback and is copied
somewhere writable first.
2. The engine's paths.py knows two worlds - frozen (ProgramData) and a
checkout (the repo root) - and a pip-installed engine is neither. It
resolved its state root to site-packages: database there, camera
list there, and its generated API credential in a folder the app
never reads, while the app looked in ProgramData. Every call would be
401 on a stock install, with nothing in either log saying why. The
same disease as the Mac checkout two days ago, now in production
shape.
engine.ChildEnv is the one place the engine's environment is built,
used by the desktop app, the headless agent and the installer's own
smoke test. It passes BEHAVISION_DATA_DIR = this process's state
root, which paths.py honours ahead of every other rule, so the two
halves agree by construction however the engine was installed.
It also seeds config/default.yaml into the state root: a package in
site-packages has no config beside it to seed from.
Re-run on the same clean container: seven steps, all pass, models
downloaded, engine started and answered, and its data/ landed beside
agent.json - not in site-packages.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KGcjxF1cNLcuwc3DAPcnfj
Five components that ship as one product:
- behavision/ the recognition engine. RTSP ingest, YuNet detection, IoU
tracking, ArcFace embeddings, a FAISS/SQLite gallery, and a
FastAPI dashboard. Identity is decided once per TRACK from an
average of at least three embeddings, never per frame.
- agent/ the Go edge agent: supervises the engine, holds a durable
spool, and drains it to MQTT. Nothing is acked before the
broker confirms.
- desktop/ the shop PC application (Wails + React + tray).
- server/ the cloud API, MQTT consumer, reports and assistant.
- web/ platform.loyaly.ai, the head-office app, embedded in the
server binary.
The gallery stores 512-float embeddings and timestamps - no images unless
`app.store_faces` is switched on. Those embeddings are biometric personal
data under GDPR and India's DPDP: template inversion reconstructs a
recognisable face from an ArcFace vector, so data/behavision.db is treated
as a biometric database and DELETE /api/visitors/{id} is a real erasure.
CLAUDE.md carries the reasoning behind every non-obvious decision here,
including the ones that were measured and the ones that were wrong first.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HViLj9gYNRtSr7YVZmW5sn