Finishing the last commit, which traded a simpler definition for noisier call
sites: deleting the arity ladders left `(symbol/resolver sym st pal/index-of
nil nil)` at twenty-odd places, and two trailing nils tell a reader nothing
except to go and count positions.
The ladder was a symptom. The disease is five positional parameters, and the
split that matters is which of them are OPTIONAL:
store, palette positional, because neither is optional. A dense channel
cannot be read without the store it names — that is the
crash two commits ago — and every op carries a colour.
pose-tracks one call site, in `clip/resolver`'s own recursion
source/picture-fps two call sites
So the last three become one `opts` map, and the common call loses a nil. The
point is not the nil: it is that the sixth option, whenever it arrives, is a
key at one call site rather than a nil at fifty.
`clip/resolver` also had `sid` FOURTH, behind two arguments that say nothing
about which symbol is being resolved. It is second now, beside the clip it is
in: `(clip/resolver c :main store pal/index-of nil)`.
62 call sites rewritten by parsing the forms rather than by regex, because
`clip/resolver`'s arguments move past each other and a regex cannot see that.
An earlier attempt at this dropped `palette` on the floor and still compiled
at 62 sites — it only surfaced as an arity error, so if that had been a
same-arity mistake the tests would have been the last line of defence.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
68 lines
3.4 KiB
Clojure
68 lines
3.4 KiB
Clojure
(ns arthur.flow.eye-occlusion-test
|
|
(:require [cljs.test :refer [deftest is]]
|
|
[arthur.demo.take :as take]
|
|
[arthur.domain.channel :as ch]
|
|
[arthur.domain.clip :as clip]
|
|
[arthur.domain.landmarks :as lm]
|
|
[arthur.domain.palette :as pal]
|
|
[arthur.domain.symbol :as symbol]
|
|
[arthur.flow.condition.eyes :as condition-eyes]
|
|
[arthur.flow.ingest :as ingest]
|
|
[arthur.flow.measure.eyes :as eyes]
|
|
[arthur.flow.take :as flow-take]))
|
|
|
|
(deftest an-unobserved-eye-cannot-steer-the-shared-gaze
|
|
(let [frame 11
|
|
params (assoc take/params :aspect 1)
|
|
presence (ingest/feature-presence take/frames {:eye-r [[10 14]]})
|
|
inputs {:dense @take/analysis
|
|
:transforms (:transforms @take/measured)
|
|
:presence presence}
|
|
clean (eyes/measure params inputs)
|
|
iris-ids (if (= :a (:right (:iris-pair clean))) lm/IRIS-A lm/IRIS-B)
|
|
bad-ids (distinct (concat lm/EYE-R-RING iris-ids))
|
|
corrupted (mapv (fn [i source]
|
|
(if (<= 9 i 13)
|
|
(reduce (fn [points id]
|
|
(update-in points [id :x] + 0.25))
|
|
source bad-ids)
|
|
source))
|
|
(range take/frames) @take/analysis)
|
|
masked (eyes/measure params (assoc inputs :dense corrupted))
|
|
unmasked (eyes/measure params
|
|
(dissoc (assoc inputs :dense corrupted) :presence))
|
|
drawn-clean (condition-eyes/apply-defaults params clean)
|
|
drawn-masked (condition-eyes/apply-defaults params masked)]
|
|
(is (= lm/NUM-LANDMARKS (count (nth corrupted frame))))
|
|
(is (:has-iris? masked) (str "pair " (:iris-pair masked)))
|
|
(is (false? (nth (:observed-r masked) frame)))
|
|
(is (true? (nth (:observed-l masked) frame)))
|
|
(is (= (nth (:gaze clean) frame) (nth (:gaze masked) frame)))
|
|
(is (not= (nth (:gaze clean) frame) (nth (:gaze unmasked) frame)))
|
|
(is (= (nth (:lid-r drawn-clean) frame)
|
|
(nth (:lid-r drawn-masked) frame)))
|
|
(is (= (nth (:iris-l drawn-clean) frame)
|
|
(nth (:iris-l drawn-masked) frame)))))
|
|
|
|
(deftest the-full-take-hides-only-the-annotated-eye-and-returns-to-the-same-id
|
|
(let [presence (ingest/feature-presence take/frames {:eye-r [[10 14]]})
|
|
{:keys [clip store]} (flow-take/build
|
|
(assoc take/params :aspect 1 :name "observed-gap")
|
|
{:face-1 {:dense @take/analysis :presence presence}})
|
|
sample (fn [id frame]
|
|
(ch/value-at (get-in (:nodes (clip/symbol clip :face-1)) [id :channels [:geom :pts]])
|
|
frame store))]
|
|
(is (empty? (clip/problems clip)))
|
|
(is (= [:face-1/eye-r :face-1/eye-l] (get-in clip [:groups :face-1/eyes :members])))
|
|
(doseq [f (range 9 14)]
|
|
(is (ch/nothing? (sample :eye-r f)))
|
|
(is (not (ch/nothing? (sample :eye-l f))))
|
|
(is (not (ch/nothing? (sample :mouth f)))))
|
|
(let [drawn (into #{} (map :node)
|
|
((symbol/resolver (clip/symbol clip :face-1) store pal/index-of nil) 11))]
|
|
(is (not (contains? drawn :eye-r)))
|
|
(is (not (contains? drawn :iris-r)))
|
|
(is (contains? drawn :eye-l))
|
|
(is (contains? drawn :mouth)))
|
|
(is (not (ch/nothing? (sample :eye-r 8))))
|
|
(is (not (ch/nothing? (sample :eye-r 14))))))
|