vrek: live video slice done; recording design and motion event findings

- First live-video slice closed: both cameras watched live on main and
  sub (4 of the goal's 6 checks), leftover-MediaMTX cleanup confirmed.
- Recording decided: motion-triggered clips, no pre-roll, 7-day
  retention, stored under .data with an env override, stream by config.
- Motion source decided: ONVIF VideoSource/MotionAlarm; Hikvision's
  alert stream refuses the ONVIF login (403).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
Michael Mainguy 2026-09-19 16:51:18 -05:00
parent 41021a62ad
commit 2edafdeeaf

View File

@ -821,3 +821,28 @@
{"id":"evt-2mf7gbv44fmb","type":"edge.added","subject":"ver-jra5mms","actor":"prn-q80g8mz","actor_kind":"agent","session":null,"payload":{"kind":"evidence_for","from":"ver-jra5mms","to":"iss-cbx21zy"},"at":"2026-09-19T21:40:00.027Z","parents":["evt-f58yed61x6g9"],"hash":"d162456933fd05a2e6e019e5106a569ef7635cea9018d32972b1c3b143df207f"}
{"id":"evt-w404t95c5wxk","type":"verification.recorded","subject":"ver-jra5mms","actor":"prn-q80g8mz","actor_kind":"agent","session":null,"payload":{"result":"pass","evidence":"User on 2026-09-19: \"looks good\", both cameras, main and sub (measurement mea for gol-sxakryh, value 4 of 6)."},"at":"2026-09-19T21:40:00.028Z","parents":["evt-2mf7gbv44fmb"],"hash":"f54aa94f712f9045480d6c6a0e29d17c3c2791405805ecb3aafab5b8bd36f9d3"}
{"id":"evt-ew0n4dq70n0y","type":"node.status_changed","subject":"iss-cbx21zy","actor":"prn-q80g8mz","actor_kind":"agent","session":null,"payload":{"from":"in_progress","to":"done"},"at":"2026-09-19T21:40:01.764Z","parents":["evt-w404t95c5wxk"],"hash":"44defac6820b215f010e288c5dd6d875b0d6a0608439728ce7231e10999f0a6f"}
{"id":"evt-w1yxzjdqq09b","type":"node.created","subject":"ver-5z3ts6x","actor":"prn-q80g8mz","actor_kind":"agent","session":null,"payload":{"kind":"verification","title":"Real check by the user: after force-killing the server, the next start stops the leftover MediaMTX and starts a new one normally","body":"","status":"pending","owner":"prn-q80g8mz","attrs":{}},"at":"2026-09-19T21:41:16.914Z","parents":["evt-ew0n4dq70n0y"],"hash":"336f262c4593932f7cb7d0b8fd2dedff4512d110913bd407a8104622b919a04a"}
{"id":"evt-6264hv25s2zd","type":"edge.added","subject":"ver-5z3ts6x","actor":"prn-q80g8mz","actor_kind":"agent","session":null,"payload":{"kind":"evidence_for","from":"ver-5z3ts6x","to":"iss-yd2sq2q"},"at":"2026-09-19T21:41:16.915Z","parents":["evt-w1yxzjdqq09b"],"hash":"7ac4403f3783e6dbf707c923c39fc135d60f11a95a1b71d5268c09abb9d42b8d"}
{"id":"evt-55f353kkgk7e","type":"verification.recorded","subject":"ver-5z3ts6x","actor":"prn-q80g8mz","actor_kind":"agent","session":null,"payload":{"result":"pass","evidence":"User's dev server log on 2026-09-19 16:40:56: \"[video] stopped a MediaMTX left running by an earlier server (stopped)\", followed by MediaMTX v1.21.0 starting with its usual localhost listeners; the dashboard then served info and snapshot requests normally."},"at":"2026-09-19T21:41:16.916Z","parents":["evt-6264hv25s2zd"],"hash":"fa9da9d18144b3986d8788ba4a1a14e943bb0a375e6f4702e9f0dd195a78dadf"}
{"id":"evt-2qaq4pkj2rp2","type":"node.status_changed","subject":"iss-yd2sq2q","actor":"prn-q80g8mz","actor_kind":"agent","session":null,"payload":{"from":"in_progress","to":"done"},"at":"2026-09-19T21:41:18.548Z","parents":["evt-55f353kkgk7e"],"hash":"a7fec7c639d5cba7229dcac3a8252b12b15a4a51ff47a216c02646a76d07ebc4"}
{"id":"evt-4vc7pdzkspy4","type":"node.created","subject":"ver-k4vv5k5","actor":"prn-q80g8mz","actor_kind":"agent","session":null,"payload":{"kind":"verification","title":"First slice complete: every child closed, and the user has watched both cameras live in the pop-out and on the camera page behind the admin session","body":"","status":"pending","owner":"prn-q80g8mz","attrs":{}},"at":"2026-09-19T21:41:20.308Z","parents":["evt-2qaq4pkj2rp2"],"hash":"c1352b97301f262b32584c3a94099884c9207b0da5637ea956ff49cdc54ec2a2"}
{"id":"evt-xggtmgdgjebx","type":"edge.added","subject":"ver-k4vv5k5","actor":"prn-q80g8mz","actor_kind":"agent","session":null,"payload":{"kind":"evidence_for","from":"ver-k4vv5k5","to":"iss-4atmz13"},"at":"2026-09-19T21:41:20.309Z","parents":["evt-4vc7pdzkspy4"],"hash":"8a13d91e27c50547bfa59405618b466933e348e4c2fd894c6840774004045bd5"}
{"id":"evt-n40y7wbr2hbd","type":"verification.recorded","subject":"ver-k4vv5k5","actor":"prn-q80g8mz","actor_kind":"agent","session":null,"payload":{"result":"pass","evidence":"Children iss-5xkn65m, iss-qdc4vqw, iss-nk6zrzv, iss-cbx21zy and iss-yd2sq2q are done with their own evidence. User watched both cameras on main and sub on 2026-09-19 (mea-95yr6gy, 4 of the goal's 6 checks). Commits 5824db8 and 41021a6."},"at":"2026-09-19T21:41:20.310Z","parents":["evt-xggtmgdgjebx"],"hash":"c13f0e6985013f4fe145e0b889d62c2f47ae53f9018e718df6fa35f8bfed8c29"}
{"id":"evt-w69ds2hrjjap","type":"node.status_changed","subject":"iss-4atmz13","actor":"prn-q80g8mz","actor_kind":"agent","session":null,"payload":{"from":"open","to":"done"},"at":"2026-09-19T21:41:22.275Z","parents":["evt-n40y7wbr2hbd"],"hash":"9cb35d1b86150eee9f7fd4c352b36409d3d9f57417ec38648f37adccfdb7d50d"}
{"id":"evt-kwy0vjrsd4c4","type":"node.created","subject":"dec-9z8vdmj","actor":"prn-q80g8mz","actor_kind":"agent","session":null,"payload":{"kind":"decision","title":"Recording: motion-triggered clips with no pre-roll, kept 7 days, in .data (env-overridable), stream chosen by configuration","body":"User's answers on 2026-09-19 while designing iss-g456j72, under gol-sxakryh and dec-9xrjx82. (1) Storage: clips go under the .data directory, with an environment variable to override the location (e.g. RECORDINGS_DIR), so an external drive or NAS can be used without code changes. (2) Clips start when motion is reported and stop a few seconds after it ends; no pre-roll, since MediaMTX keeps no buffer of what came before and continuous recording was rejected for now. The first moment of movement may be missed because cameras report motion slightly late. (3) Which stream is recorded is a configuration option per the user, not a fixed choice; the default should be the sub stream (about 5 MB per minute of motion) with main (about 38 MB per minute) available. (4) Retention: delete clips older than 7 days, which MediaMTX does itself (recordDeleteAfter). (5) Event source: check both ONVIF events and the Hikvision alert stream read-only on one camera first, then decide with evidence, rather than assuming ONVIF works on these cameras.","status":"recorded","owner":"prn-q80g8mz","attrs":{}},"at":"2026-09-19T21:44:42.461Z","parents":["evt-w69ds2hrjjap"],"hash":"782b31386f891ac78649998ef231a5be2f2748b7c73f9ca77b1d3f89dc924026"}
{"id":"evt-ms7s9cx05sfw","type":"edge.added","subject":"dec-9z8vdmj","actor":"prn-q80g8mz","actor_kind":"agent","session":null,"payload":{"kind":"serves","from":"dec-9z8vdmj","to":"gol-sxakryh"},"at":"2026-09-19T21:44:42.464Z","parents":["evt-kwy0vjrsd4c4"],"hash":"286c93e2f28115e607ae3a77572ce7807e68268603f38eaa83b07ae511614949"}
{"id":"evt-2zg9qga5ks7x","type":"node.created","subject":"iss-hdt480y","actor":"prn-q80g8mz","actor_kind":"agent","session":null,"payload":{"kind":"issue","title":"Check motion event feeds read-only: ONVIF events vs Hikvision alert stream","body":"Per dec-9z8vdmj, before any recording work. On one camera, read-only: (1) ONVIF — GetEventProperties for the topics offered, then a PullPointSubscription for about a minute, waving at the camera, and record which topics arrive (RuleEngine/CellMotionDetector, VideoSource/MotionAlarm, …) and how quickly. (2) Hikvision — GET /ISAPI/Event/notification/alertStream (digest, multipart) for about a minute, recording the event types and timing; today's probe showed the ONVIF login is accepted by ISAPI but the picture endpoint answered Device Busy, so this may not work either. Record both as findings (no IPs or serials, per dec-kgm44qw), then decide the event source. Needs the user's go-ahead: it subscribes to the camera rather than only reading.","status":"open","owner":null,"attrs":{}},"at":"2026-09-19T21:44:52.191Z","parents":["evt-ms7s9cx05sfw"],"hash":"9031d55bf3fc939168cdd41b3a1c9f28213b06a47f4dfed0a9cd52e31970ab51"}
{"id":"evt-79hvbpc2j14f","type":"edge.added","subject":"iss-hdt480y","actor":"prn-q80g8mz","actor_kind":"agent","session":null,"payload":{"kind":"serves","from":"iss-hdt480y","to":"gol-sxakryh"},"at":"2026-09-19T21:44:52.192Z","parents":["evt-2zg9qga5ks7x"],"hash":"e067593bd1e1143992ffc2b5516e68e5f2c2ec6747394879c1ce4e15290d6da6"}
{"id":"evt-3da1a83twh35","type":"edge.added","subject":"iss-g456j72","actor":"prn-q80g8mz","actor_kind":"agent","session":null,"payload":{"kind":"parent_of","from":"iss-g456j72","to":"iss-hdt480y"},"at":"2026-09-19T21:44:52.193Z","parents":["evt-79hvbpc2j14f"],"hash":"98a35912a4ccac2085a9292195286973fa15ab20bbbd267824f99a9ebd4c4127"}
{"id":"evt-v5pmc08pksx6","type":"edge.added","subject":"iss-hdt480y","actor":"prn-q80g8mz","actor_kind":"agent","session":null,"payload":{"kind":"tagged","from":"iss-hdt480y","to":"area:video"},"at":"2026-09-19T21:44:52.194Z","parents":["evt-3da1a83twh35"],"hash":"75c71922afa40442cd9437caaae4e36012ad32899a41a45c44824bcd598d0289"}
{"id":"evt-pdttwz00qz5b","type":"edge.added","subject":"iss-hdt480y","actor":"prn-q80g8mz","actor_kind":"agent","session":null,"payload":{"kind":"tagged","from":"iss-hdt480y","to":"area:device"},"at":"2026-09-19T21:44:52.195Z","parents":["evt-v5pmc08pksx6"],"hash":"b3a52bd4efb187d1aa1d901a7874697849f50118903e28a88f3151ff20be1cca"}
{"id":"evt-x11eb0bntkw9","type":"node.updated","subject":"iss-g456j72","actor":"prn-q80g8mz","actor_kind":"agent","session":null,"payload":{"patch":{"body":"Motion-triggered recording, designed per dec-9z8vdmj (answers given 2026-09-19). Clips start when motion is reported and stop a few seconds after it ends: no pre-roll, because MediaMTX holds no buffer of what came before. Storage under .data, overridable with an environment variable (RECORDINGS_DIR) so an external drive or NAS can be used. Which stream is recorded is a configuration option, defaulting to the sub stream (about 5 MB per minute of motion; main is about 38 MB). Retention: MediaMTX deletes clips older than 7 days (recordDeleteAfter: 7d, recordFormat fmp4). Recording is switched on and off per path over MediaMTX's localhost API as events arrive. The event source is decided by the read-only check in the child issue. Still to design after that: how clips are listed, played and deleted behind the admin session, and what the dashboard shows when a camera is recording. The goal's last 2 checks are one recorded and played-back motion clip per camera."}},"at":"2026-09-19T21:44:56.541Z","parents":["evt-pdttwz00qz5b"],"hash":"42fb6fc8aa29c864e63d486bea7b4718e684781b5a136614c8d0049a3f099964"}
{"id":"evt-s71rh42bj7hk","type":"node.created","subject":"fnd-3kp0rwy","actor":"prn-q80g8mz","actor_kind":"agent","session":null,"payload":{"kind":"finding","title":"Camera …af54 reports motion over ONVIF within seconds; Hikvision's alert stream refuses the ONVIF login with 403","body":"Read-only probe on 2026-09-19 with the stored Operator ONVIF login, about 100 seconds, while the user walked in front of the camera. ONVIF PullPoint delivered events immediately and repeated the full state about once a second. Topics seen: tns1:VideoSource/MotionAlarm (State), tns1:RuleEngine/CellMotionDetector/Motion (IsMotion), tns1:RuleEngine/TamperDetector/Tamper, tns1:VideoSource/ImageTooDark/ImagingService, tns1:Monitoring/OperatingTime/{LastReset,LastReboot,LastClockSynchronization}, tns1:Monitoring/ProcessorUsage, tns1:Device/HardwareFailure/StorageFailure. MotionAlarm tracked the walking: false at start, true at 8.8 s, false at 36.9 s, true at 57.7 s, false at 75.7 s. CellMotionDetector/Motion went true at 8.9 s but stayed true until 75.8 s, so it is much slower to clear and is the worse trigger. GetEventProperties returned a shape this probe's parser didn't read, so the offered topic list wasn't captured; the live events are the evidence. Hikvision /ISAPI/Event/notification/alertStream answered HTTP 403 application/xml for this login, matching the ISAPI picture refusal (fnd-k1jyt83). Caveat: the onvif library logged \"Parse Error: Data after `Connection: close`\" several times during the run; it recovered each time, but a recording controller must tolerate dropped pulls and re-subscribe.","status":"current","owner":"prn-q80g8mz","attrs":{"sources":[{"url":"http://localhost/onvif/device_service","note":"Camera …af54 (address redacted per dec-kgm44qw): ONVIF PullPoint via the onvif library, plus /ISAPI/Event/notification/alertStream; scratch script run from .data and deleted afterwards"}],"as_of":"2026-09-19"}},"at":"2026-09-19T21:50:06.223Z","parents":["evt-x11eb0bntkw9"],"hash":"7e423b20dc4113cf291605f7deb7406b5d5379a0d337f54357fa3a50aeac9a35"}
{"id":"evt-5yg9w820fp5f","type":"edge.added","subject":"fnd-3kp0rwy","actor":"prn-q80g8mz","actor_kind":"agent","session":null,"payload":{"kind":"informs","from":"fnd-3kp0rwy","to":"iss-hdt480y"},"at":"2026-09-19T21:50:06.224Z","parents":["evt-s71rh42bj7hk"],"hash":"5ff8a879774111421fa9cf9d5d25a1f216101d82b3239cfb12c1c951df5474f8"}
{"id":"evt-7x7h9eh0t7d8","type":"edge.added","subject":"fnd-3kp0rwy","actor":"prn-q80g8mz","actor_kind":"agent","session":null,"payload":{"kind":"informs","from":"fnd-3kp0rwy","to":"iss-g456j72"},"at":"2026-09-19T21:50:06.225Z","parents":["evt-5yg9w820fp5f"],"hash":"0505ae3c1b968677bb8cc84f9455c9948856482e92d5220fc4208f2aaefe4498"}
{"id":"evt-kdnkm81nr5nk","type":"edge.added","subject":"fnd-3kp0rwy","actor":"prn-q80g8mz","actor_kind":"agent","session":null,"payload":{"kind":"informs","from":"fnd-3kp0rwy","to":"gol-sxakryh"},"at":"2026-09-19T21:50:06.226Z","parents":["evt-7x7h9eh0t7d8"],"hash":"d8c2d5f5241b411201b192cadac5ec79a4b7b9ef38b5c6ed545560b95b665113"}
{"id":"evt-r81bw4h3c3yb","type":"edge.added","subject":"fnd-3kp0rwy","actor":"prn-q80g8mz","actor_kind":"agent","session":null,"payload":{"kind":"discovered_from","from":"fnd-3kp0rwy","to":"iss-hdt480y"},"at":"2026-09-19T21:50:06.227Z","parents":["evt-kdnkm81nr5nk"],"hash":"c34c51f0850ab2e5de1d50646eec51b55464ed237ba2d7376defcb26c00b6126"}
{"id":"evt-v6w9rsx8erzq","type":"node.created","subject":"dec-d50j69a","actor":"prn-q80g8mz","actor_kind":"agent","session":null,"payload":{"kind":"decision","title":"Motion comes from ONVIF events, triggering on VideoSource/MotionAlarm","body":"Per fnd-srfdnmm and the probe in fnd-dw1pqcw's successor: ONVIF PullPoint works on camera …af54 with the Operator login and reports motion within seconds, while Hikvision's alert stream refuses that login with 403. So recording triggers on ONVIF, which also keeps the app vendor-neutral (pri-p9h51hx). Use tns1:VideoSource/MotionAlarm, whose State follows movement closely (true about 9 s after walking started, false about 20 s after stopping). Do not use RuleEngine/CellMotionDetector/Motion: it went true at the same moment but stayed true for over a minute after movement ended. The camera repeats its whole state about once a second, so the controller acts on changes, not on every message, and it must survive dropped pulls: the onvif library logged repeated parse errors during the probe and recovered, so re-subscribing has to be automatic. ISAPI remains unused; revisit only if a web-account login is ever added.","status":"recorded","owner":"prn-q80g8mz","attrs":{}},"at":"2026-09-19T21:50:12.326Z","parents":["evt-r81bw4h3c3yb"],"hash":"8d1a17d054f2733c3c4f9a4fc56de296ebf793cca7a6dcc7d1df92c37da9da78"}
{"id":"evt-90ck7pe92yzb","type":"edge.added","subject":"dec-d50j69a","actor":"prn-q80g8mz","actor_kind":"agent","session":null,"payload":{"kind":"answers","from":"dec-d50j69a","to":"iss-hdt480y"},"at":"2026-09-19T21:50:12.327Z","parents":["evt-v6w9rsx8erzq"],"hash":"86675848af2322f42bf9c4453467e1633bb947ebc64f7b5e70a63ad8c842b9a6"}
{"id":"evt-hq3cwd9sq2kb","type":"edge.added","subject":"dec-d50j69a","actor":"prn-q80g8mz","actor_kind":"agent","session":null,"payload":{"kind":"serves","from":"dec-d50j69a","to":"gol-sxakryh"},"at":"2026-09-19T21:50:12.328Z","parents":["evt-90ck7pe92yzb"],"hash":"75118130559649fcbe4d30f7eab54e5734dad48b2954fb7be7b4898204899bcd"}
{"id":"evt-3w4qpcc7n1qv","type":"node.status_changed","subject":"iss-hdt480y","actor":"prn-q80g8mz","actor_kind":"agent","session":null,"payload":{"from":"open","to":"done"},"at":"2026-09-19T21:50:16.490Z","parents":["evt-hq3cwd9sq2kb"],"hash":"0930689ca703fb569f1f4a20b5e04888fde27ca44db69abd4f9234fe5fb18218"}