Two identity fixes, neither yet run on a GPU. has_face, the extras gate: fixing the bbox coordinate space made extras worse, because crops finally landed on their subjects and a background extra bound to the lead at 1.00. /vision stamps has_face per character using face_detect and _pair_faces_to_present, so containment and its margin match the speaker path. Identity skips has_face is False before it crops or embeds. Fails open on a missing or raising detector, and gates on `is False` so an older vision blob behaves as before. The NONE mint: /identity/resolve now writes each crop's embedding to the crop's key with a .npy suffix and returns emb_uri. The orchestrator cannot compute an embedding of its own (siglip and gemma cannot both be resident), which is why it was clearing a deliberate NONE instead of minting an anonymous character. Also: audit_registry.py, and the tmux respawn-window trap, which leaves a bare shell rather than re-running the window command. decisions/identity-bbox.md#face-gates-enrollment decisions/identity-bbox.md#none-mints-an-anonymous-character Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
5.8 KiB
HANDOFF, 2026-08-12 (third session of the day)
Live state is in NEXT.md. This file is only what this session did. The previous handoff is in
JOURNAL.md.
Asked
Move on from the chapter rebuild. Scope chosen mid-session: reset the registry, rerun vision,
identity and reconcile only, inspect, then decide about the ~80 minutes downstream. After the
inspection the user chose to fix extras-versus-cast before running downstream.
Result
The identity rebaseline ran and the numbers moved a long way. One code change on top of it is written and self-checked but not yet proven on a GPU run.
before stale run after
x2 past panel width 47/113 46/110 0/110
coords exactly on 1000 21 27 1
max y2 1000 1000 2307
characters 19 8 8
coverage 26/113 = 23% 77/110 = 70% 77/110 = 70%
top character's share 96% Haeseon 47% 47%
Choi Haeseon, which held 25 of 26 assignments, is gone from the registry. Panel 7 against the art:
| box | who | before | after |
|---|---|---|---|
[457, 657, 642, 937] |
Seonho, foreground | nothing | Seonho |
[669, 591, 763, 822] |
the colleague, unnamed in the story | Choi Haeseon 0.9 |
character_f7a4fd |
[428, 386, 496, 526] |
background extra | extra as cast | none |
[34, 414, 122, 564] |
background extra | extra as cast | none |
[498, 386, 568, 533] |
background extra | extra as cast | character_d72710 0.94 |
[31, 554, 94, 728] |
background extra | Lim Seonho |
Seonho 1.00 |
The run that did not count
The first full cycle completed 116/116/20 and reproduced the defect exactly. The fix was not wrong, it was not loaded:
vision worker started 12:00:09
worker_vision.py modified 12:11:35
8113bdf, carrying _bbox_to_pixels 12:16:22
Python binds a module once, at process start. The stage reported success and the orchestrator recorded
no error. Cost: one vision + identity + reconcile cycle and a second registry reset to undo the 8
characters it minted. decisions/identity-bbox.md#stale-worker-invalidates.
./check_stale.sh now compares every running worker's start time against its module mtime and exits
non-zero. Mutation-tested. Run it before any stage run meant to prove a code change.
Written this session
db.reset_registry+POST /characters/reset(confirm=true)./stage/clearsparescharactersby design (db.py:790), so nothing could rebaseline the registry. Also clearsidentity_assignment_sources, which no stage clear touches and where a leftovermanualrow makesassign_identityrefuse the next model assignment (db.py:663). Covered bytest_db.py:TestResetRegistry. Orchestrator, committed on homesrv, image rebuilt.check_stale.sh,audit_registry.py(runs insidemanga-orchestrator, alreadydocker cp'd).has_face, the extras gate. This is the part not yet proven. Fixing the coordinate space made extras worse. With crops finally on their subjects, an extra bound to the lead at 1.00./visionstampshas_faceper character usingface_detect+_pair_faces_to_present, so containment and its margin are the rules the speaker path already uses.worker_identity.pyskipshas_face is Falsebefore it crops or embeds. Fails open on a missing or raising detector, and gates onis Falseso an older vision blob behaves as before.decisions/identity-bbox.md#face-gates-enrollment.
Checks
.venv/bin/python worker_vision.py # includes the has_face gate + both fail-open paths
.venv/bin/python worker_identity.py
./check_stale.sh # exits non-zero if a worker predates its file
cd /home/kami/docker-apps/manga-infra/orchestrator && python3 -m pytest -q --ignore=test_api.py # 115 passed, on homesrv
Next command
The has_face gate has never run on a GPU. Restart vision and identity, reset, rerun, and check whether
the two wrong bindings on panel 7 disappear without taking Seonho with them.
cd /home/kami/Programs/n8n-worker && ./check_stale.sh # restart anything it flags
J=778297bc-e7ce-439d-91b5-8a027060d17f; M=ef105a86-4b7e-4ac4-b45c-b7d83b8f5b5e
/usr/bin/ssh kami@192.168.1.104 "curl -s -X POST http://127.0.0.1:9090/characters/reset -H 'Content-Type: application/json' -d '{\"manga_id\":\"$M\",\"confirm\":true}'"
/usr/bin/ssh kami@192.168.1.104 "curl -s -X POST http://127.0.0.1:9090/stage/clear -H 'Content-Type: application/json' -d '{\"job_id\":\"$J\",\"stage\":\"vision\"}'"
for S in vision identity reconcile; do /usr/bin/ssh kami@192.168.1.104 "curl -s --max-time 5400 -X POST http://127.0.0.1:9090/stage/run -H 'Content-Type: application/json' -d '{\"job_id\":\"$J\",\"stage\":\"$S\"}'"; done
/usr/bin/ssh kami@192.168.1.104 "docker exec manga-orchestrator python3 /app/audit_registry.py 7c944dd4-e972-42c7-ba60-9f6939548e80 6"
Watch for coverage collapsing. 70% is the number to beat. A gate that abstains too hard shows up there before it shows up on panel 7. Restart the identity worker after every reset: it caches the known list in-process and only invalidates on enrollment.
Gone
The rebuilt chapter.mp4 and all 49 clips were deleted by the cascade from /stage/clear vision. The
user chose not to keep a copy. Nothing downstream of reconcile exists for this job now.
Traps confirmed again
- A stage reporting
completed 116/116says the code ran, not that the current code ran. - The SSHFS mount at
/mnt/server/home/kamiwas absent and needed remounting by the user, since the mountpoint needs root. - The orchestrator image bakes its source. Editing the repo on homesrv does nothing until
docker compose up -d --build orchestrator. rtk grepsearches files, not stdin. Piping into it silently searches the repo instead.