Restore the runtime and bring master up to the seventh session #1

Merged
claude merged 31 commits from restore-runtime into master 2026-08-13 21:07:14 +02:00
Contributor

Brings master up to the current state of the pipeline. master holds only the reconstruction commit. Every session since lives on this branch.

What this is

The workpc compute half of a manga to narrated-video pipeline: stateless GPU and CPU workers behind a fixed HTTP contract. State and stage orchestration live in the separate homesrv orchestrator repo. That repo is reconciled in lockstep whenever a request or response shape changes.

The arc, oldest to newest

Runtime restore. Models, dots.tts and the torchvision shadow put back after the loss.

Phase 1 audit. Correctness and scheduling safety, then a cross-repo pass over the worker/orchestrator contract. Findings are filed in decisions/audit-phase1.md, not restated in prose.

Storage. Artifacts split one bucket per class. stowage serves the manga buckets. rustfs is staged and empty, and MinIO still serves every read and write.

Speaker attribution. A model guess is no longer labelled as a read tail. Gemma's answer maps back to a present character. The honest speaker number is 9%.

The first end-to-end chapter, and two stages that reported success while writing nothing.

A/V sync. Two separate defects. xfade offsets ran off the end of their input, and a stream copy crossed mixed frame rates. chapter.mp4 now runs video 364.120s against audio 364.122s. Invariant 9 exists because format=duration reports max(video, audio) and hides both.

Identity, the bulk of the recent work. Five changes, in the order they landed:

  • the bbox coordinate space settled, proven over 113 detections
  • a resolver NONE mints an anonymous character instead of being discarded
  • has_face gates enrollment and two downstream consumers
  • reconcile stopped deleting the losing row, so a wrong merge costs a SQL walk rather than a rebaseline
  • the resolver gallery became the live cast rather than cosine's top-k

Four GPU cycles back these. The last cycle measured 119 detections and 60 assignments. The lead holds 16 rather than 36, and reconcile leaves 14 characters. Checked crop by crop by eye.

Naming. Three fixes in db.add_name_claim, written against a real dialogue run and not yet exercised on a GPU.

Architecture. The target shape, written under the constraint that Magi and any learned head are ruled out. Every section carries what exists today and a DoD. The build order starts at step 0, the measurement spine.

State at merge

The chapter runs end to end. The job is parked at dialogue waiting. Four changes are written and tested but have not touched a GPU: the wired caption merge and the three naming fixes. NEXT.md holds the live plan and the exact next command.

Reading order

CLAUDE.md first. It is a pointer table, and the goal and invariants live there. NEXT.md is the current state, ARCHITECTURE.md is the target, decisions/ and caveats/ hold every settled question and known limit.

Checks

No lint or build step. Every module carries an assert-based __main__ self-check. The orchestrator suite runs 121 tests.

Brings `master` up to the current state of the pipeline. `master` holds only the reconstruction commit. Every session since lives on this branch. ## What this is The workpc compute half of a manga to narrated-video pipeline: stateless GPU and CPU workers behind a fixed HTTP contract. State and stage orchestration live in the separate homesrv orchestrator repo. That repo is reconciled in lockstep whenever a request or response shape changes. ## The arc, oldest to newest **Runtime restore.** Models, `dots.tts` and the torchvision shadow put back after the loss. **Phase 1 audit.** Correctness and scheduling safety, then a cross-repo pass over the worker/orchestrator contract. Findings are filed in `decisions/audit-phase1.md`, not restated in prose. **Storage.** Artifacts split one bucket per class. `stowage` serves the manga buckets. `rustfs` is staged and empty, and MinIO still serves every read and write. **Speaker attribution.** A model guess is no longer labelled as a read tail. Gemma's answer maps back to a present character. The honest speaker number is 9%. **The first end-to-end chapter,** and two stages that reported success while writing nothing. **A/V sync.** Two separate defects. `xfade` offsets ran off the end of their input, and a stream copy crossed mixed frame rates. `chapter.mp4` now runs video 364.120s against audio 364.122s. Invariant 9 exists because `format=duration` reports `max(video, audio)` and hides both. **Identity, the bulk of the recent work.** Five changes, in the order they landed: - the `bbox` coordinate space settled, proven over 113 detections - a resolver NONE mints an anonymous character instead of being discarded - `has_face` gates enrollment and two downstream consumers - reconcile stopped deleting the losing row, so a wrong merge costs a SQL walk rather than a rebaseline - the resolver gallery became the live cast rather than cosine's top-k Four GPU cycles back these. The last cycle measured 119 detections and 60 assignments. The lead holds 16 rather than 36, and reconcile leaves 14 characters. Checked crop by crop by eye. **Naming.** Three fixes in `db.add_name_claim`, written against a real dialogue run and not yet exercised on a GPU. **Architecture.** The target shape, written under the constraint that Magi and any learned head are ruled out. Every section carries what exists today and a DoD. The build order starts at step 0, the measurement spine. ## State at merge The chapter runs end to end. The job is parked at `dialogue waiting`. Four changes are written and tested but have not touched a GPU: the wired caption merge and the three naming fixes. `NEXT.md` holds the live plan and the exact next command. ## Reading order `CLAUDE.md` first. It is a pointer table, and the goal and invariants live there. `NEXT.md` is the current state, `ARCHITECTURE.md` is the target, `decisions/` and `caveats/` hold every settled question and known limit. ## Checks No lint or build step. Every module carries an assert-based `__main__` self-check. The orchestrator suite runs 121 tests.
claude added 28 commits 2026-08-13 20:29:59 +02:00
Rebuild the venv half of the reconstruction. Adds the two CPU onnx
detectors back under models/ (comic-text-detector, deepghs anime face,
both gitignored), re-clones the dots.tts checkout, and records both
recipes in requirements.txt so the next rebuild skips the archaeology.

Two pre-existing environment breakages had to be cleared:

- Arch's torchvision 0.25 is too old for torch 2.13, so every
  transformers model import died with "operator torchvision::nms does
  not exist". Shadowed with 0.28.0+rocm7.2 inside the venv only, so the
  system copy stays put.
- dots_tts refuses to import when torch and torchaudio minors differ,
  and that pair is unsatisfiable here: 2.11 is the newest torchaudio
  ROCm wheel there is. Verified 2.11 loads and resamples against 2.13,
  then scoped a bypass around the import in both call sites.

Self-checks 13/14. worker_layers still needs the ComfyUI workflow json,
which legacy/ took with it.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Read the workpc workers against the homesrv orchestrator and checked the
first-pass audit against source. Report only, no code changed.

Adds 4 P0, 6 P1, and 13 P2 findings to AUDIT.md, most of them in the seam
between the two repos:

- worker_scene reads dialogue `speaker` as a local id, but the orchestrator
  already rewrote it to a character_id, so all narration says "Someone"
- the script verifier fails valid narration on sentence-initial capitals and
  on short quotes, which halts the chapter
- correctness flags block TTS with no path to clear them when GATES is off
- session_manager can orphan a llama-server that keeps its VRAM

Confirms four first-pass claims in source: tracklet gender enum, missing
action evidence, dropped verifier feedback, 409 lease stealing.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Implements every P0 from AUDIT.md plus four P1s, across both halves of the
pipeline. Verified by CPU-only self-checks and the orchestrator test suite.
No GPU work ran and no pipeline ran.

workpc:
- worker_scene: read speaker_ref, not the rewritten speaker field. Every line
  narrated as "Someone" before this. Emit `actions` for the verifier.
- worker_script: declare beat + verifier_feedback (pydantic dropped both, so
  the retry was blind) and render them as a repair prompt.
- worker_vision: gate face->identity pairing on containment, assign globally
  shortest-first, map an out-of-range resolver index to `unresolved` instead
  of minting a character, parse JSON with raw_decode.
- session_manager: tear down a server whose lease vanished mid-load, and spawn
  the supervisor respawn unlocked.

orchestrator (edited in place, NOT committed there):
- tracklets: canonicalize gender, add co-presence cannot-links, block
  transitive bridges across a hard constraint.
- correctness: stop failing valid narration on sentence-initial capitals and
  short quotes; read action evidence from the singular key.
- db: stop orphan flags leaking into every chapter; resolve by flag id.
- service: TTS returns instead of raising under GATES, auto-resolves under
  autonomous mode; job admission control; registry names on dialogue resume.
- session_proxy: queue on 409 instead of stealing the lease; run heartbeats.

Docs restructured per the repo-structure layout: CLAUDE.md is a pointer table,
NEXT.md replaces HANDOFF.md, plus ROADMAP.md, JOURNAL.md, decisions/ and
caveats/. AUDIT.md now points at those instead of restating them.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XD7cAy81MZrc7gCr6aZGWr
#117 done: stowage was dead on an arm64 digest pin, not a MinIO fault.
#116 staged: rustfs runs on 9010/9011, buckets not mirrored, no cutover.

Also logs the ISP port 80/443 interception that made three external
reachability measurements worthless, so the next session does not repeat them.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Panels, wavs, layers, clips, and the chapter mp4 leave the `manga` bucket for
`panels`, `audio`, `layers`, and `video`. The key under the bucket is unchanged,
so every reader that derives the bucket from the first path segment keeps
working. The orchestrator half moves in the same commit, per invariant 7.

The 2026-08-11 chapter run proves the split for `raw` and `panels` and produced
the first quality read on speaker attribution, which is wrong in every sampled
multi-character panel.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XD7cAy81MZrc7gCr6aZGWr
The baseline run died in `script` at 87/116. Every lost beat cites
`unsupported-proper-noun: ['Choi', 'Haeseon']`, because verify_script puts the
full name in the allowed set and then tests single capitalized tokens against
it. No fix applied.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XD7cAy81MZrc7gCr6aZGWr
_annotate_speaker_methods stamped `tail`, the highest-trust provenance, on any
line whose speaker matched a present local_id, at gemma's confidence of 1.0. No
balloon was read. Three of three sampled two-character panels had the speakers
swapped, so a multi-character guess is now dropped to unknown, and a solo-panel
guess is kept as model_solo at 0.7.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The dialogue prompt renders each present character as
`- person_1: brown ponytail, green dress (f)`, and gemma answers with what it was
shown: the description (15 lines), a bare local_id (9), a stale mark label (2),
or a name with the gender marker attached (2). All of them fell through
normalize_speaker as free-form names and never matched the registry, so 28 of 51
speech lines on job 778297bc lost a speaker the pipeline had already identified.
_apply_speaker_labels now resolves every string the prompt showed, drops an
id-shaped answer that names nobody present, and strips a trailing gender marker
so an off-panel name can still match.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
_set_of_mark labels a detected face `unknown` when gated pairing matched it to no
present character. An answer pointing at that mark grounds nothing, yet it carried
som_face, the highest-trust provenance. All 7 som_face lines in the first 36
panels of the rerun were this case. Same defect class as the fake tail label.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Adds decision entries for the unpaired set-of-mark label, the interjection
verifier false positive, and the vision-blob clearing bug, plus the per-run
speaker audit script used to measure the chapter.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The run completed: chapter.mp4 at 50MiB from 49 clips. layers reported
completed 116/116 with an empty bucket, so nothing has parallax, and the completed
job still carries the error string from a failure three resumes earlier. Both
recorded as caveats, neither fixed.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Somebody watched chapter.mp4 for the first time. Two failures came out of it
that no stage counter could see.

chapter.mp4 is video 436.39s over audio 363.67s, so narration finishes 72.7s
before the picture. The 49 clips are clean: all 25fps, video and audio agree
to 0.03s, summing to 363.6s. A per-round probe puts the loss in the final
round of _assemble_batched, which turns 359s of video into 100s while the
audio survives. Round 0 is correct. Round 1 differs by holding a 7th input,
the leftover clip that skips encoding, so the tree mixes concat output, xfade
output and a raw clip. Not fixed.

worker_render.py gains an FPS constant, fps normalization in the xfade branch
to match concat, _stream_dur, and a self-check that compares video against
audio instead of asserting the file is non-empty. That old check is how a 20%
sync failure shipped. The fps inconsistency is real but not proven to be the
shipped cause. Pinning -r on the output was tried and reverted: it drops
frames to force CFR, which the concat branch comment already warned about.

Panel 7 checked against the art has zero correct identity bindings out of two,
and Seonho, the one character who matters, is unbound. bbox values are
consumed as absolute pixels; on a 900x1650 panel that puts all six boxes in
the top third, two inside a speech balloon. Identity therefore embeds crops of
balloon edges and window frames, which is how confidence 0.9 lands on the
wrong person. The colleague has no name in the story and was labelled Choi
Haeseon; that row holds 25 of 26 assignments, so it is the label the pipeline
stamps on any unnamed woman.

Four caveats added. Two earlier claims are withdrawn in place: rescaling bbox
by 1000 does not make the boxes correct, and the constraint is not 16 nameless
rows needing names. Cast profiles already exist, since all 53 rows populate
ref_image_uris and embedding_uri, but they are enrolled from the wrong crops.

worker_render.py self-check passes. No pipeline ran.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
_xfade_chain positioned every transition using _audio_dur, which probes
format=duration, which is max(video, audio). A clip's audio outlasts its
video by about a frame, so the offset accumulator crept ahead of the real
picture timeline. Once the creep exceeded the transition width, xfade
emitted the transition and silently discarded the second input and every
clip downstream, exiting 0 with nothing on stderr. That is the whole of
the shipped chapter's 436.39s of video over 363.67s of audio.

Offsets now come from min(video, audio). Every input is floored to a
whole frame count and trimmed on both streams, so the accumulator tracks
the real timeline instead of estimating it. _check_assembled verifies
each encode against the predicted length and against its own audio,
because both assembly branches drop stream time without failing.

Verified over the 49 real clips of chapter 7c944dd4: the round that
turned 359s of video into 100s now loses 0.85s, and the chapter comes out
358.76s video against 358.76s audio.

The single-item passthrough was not the cause. Two round-0 groups of 8
fresh clips collapse without one, recorded void in decisions/.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The rebuild after 1457556 came out byte-identical to the broken file,
which proved the xfade fix never runs for this chapter. An all-cut chapter
goes down the concat demuxer with -c copy, which writes the output in the
FIRST input's time_base and reinterprets every later packet in it. 14 of
49 clips are 30/1 at 1/15360 against 35 at 25/1 at 1/12800, so those 14
play 15360/12800 = 1.2 too long with their audio untouched. collage_cmd
hardcoded -r 30 and yesterday's FPS sweep missed it.

collage_cmd now emits -r FPS, and assemble probes r_frame_rate across the
clips and routes mixed rates through the re-encoding tree. Rebuilt
chapter.mp4 is 364.120s video against 364.122s audio at 25/1, from
436.392 over 363.675.

Also settle the bbox coordinate space, measured over all 113 detections:
47 boxes have x2 past the 900px panel width, none has y2 past 1000 on
panels up to 2307px tall, and the range is exactly [0, 1000]. It is
gemma's normalized grid, not pixels, whatever the prompt asks for.
/vision converts before returning, which fixes identity's crop, the gated
face pairing that was comparing pixel face boxes against grid boxes, the
set-of-mark boxes and the review UI at once. Checked by eye on panel 7:
five of six boxes now land on their subject, including the foreground
character who had no identity.

The registry still holds boxes and embeddings enrolled from the wrong
space. vision and identity have to re-run, which is GPU work and was not
started.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
A full vision + identity + reconcile cycle ran today against a worker that had
been started before the fix it was supposed to prove. It reproduced the defect
exactly: 46 of 110 boxes past the 900px panel width, coordinates clamping at
1000, the same fingerprint measured before the fix.

    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. Editing the file afterwards
changes nothing until the process restarts, and nothing in the result says so:
the stage reported completed 116/116, the orchestrator recorded no error, and
identity and reconcile ran to completion on top of it. Cost was one cycle plus
a registry reset to undo the 8 characters it minted.

This was already known as advice. The previous handoff said the render worker
"must be restarted by hand to pick up an edit". Advice did not stop it.

check_stale.sh compares every running worker's process start against its
module's mtime and exits non-zero if any is stale, so it can gate a script.
Mutation-tested by touching worker_tts.py, which it caught.

decisions/identity-bbox.md#stale-worker-invalidates carries the evidence and
is committed separately with the rest of the session's notes.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011FmkHKFtuhppZE3B4VvNNE
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>
build_scene already dropped an unassigned detection from `characters` and
`present`, so an extra never reached the cast list. Its ACTION did. `actions` was
built from every detection, and that list is what the script prompt renders and
what the verifier uses as evidence, so "standing at the window" arrived as a fact
about the panel with no character attached and the verifier confirmed it, because
the action really was in the blob.

Skip has_face is False, the same gate and the same fail-open semantics as
enrollment. Self-check covers all three cases: a real cast member's action
survives, a faceless one's does not, and a detection from a panel where the
detector never ran keeps its action.

decisions/identity-bbox.md#extras-gate-consumers

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The registry reset deleted Lim Seonho and character_afa7623b, so there is nothing
to merge or split until the rerun mints a new set. What was done instead is the
safety net for that rerun, since reconcile runs inside it: a merge retires the
losing row rather than deleting it, and records which assignments moved.

Half-closes caveats/audit-open.md#destructive-reconcile. The unmerge path and the
split stay unwritten on purpose, with the revisit trigger named.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
HANDOFF.md now covers the fourth session: the four identity changes, the measured
numbers they were decided from, what was deliberately not built, and panel 7's
before-table so the next run has something to compare against.

AGENTS.md gains the worker-restart procedure, because tmux respawn-window -k
leaves a bare shell instead of re-running the command and took both vision and
identity down silently this session.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
No worker code changed. This is the evidence from the 2026-08-12 16:39 and
17:38 runs, and where each finding now lives.

The fourth session's four identity changes all work on real panels. Panel 7's
two wrong bindings are gone. The lead going unassigned there is correct and
was measured, not assumed: face_detect finds one face on the whole panel at
conf 0.599, nothing else above 0.056 even at a 0.04 threshold, and the crop
shows him drawn from behind.

Two decisions, both closed: a roster name is a guess so it never reaches
detection, and merged_into is exactly one hop deep. Two caveats, both open:
detection can order a bbox backwards (1 in 117), and identity coverage has
fallen on every run since the gate landed (70 -> 61 -> 50).

Coverage is the thing to settle next, and not by reading the number.
identity_labels already holds 145 rows of ground truth.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
`_bbox_to_pixels` sorts each coordinate pair after clamping. Run B returned
`p007 person_1` as `[226, 417, 130, 551]`, x1 > x2, which cropped to nothing
and lost that detection silently. The third GPU cycle came back with 0
degenerate boxes over 119 detections.

The plan's first item cannot run as written. All 145 rows of `identity_labels`
belong to chapter 8ca8249b, a different manga. Chapter 7c944dd4 has none, so
`/review/identity` reports `accuracy: null`. Scoring 8ca8249b gives 7/138 on
an identity run that predates every fix.

The cycle also settled the coverage question. All 68 assignments landed on
face-bearing detections and none on a gated one, so recall among face-bearing
detections is 96%, up from 82%. Coverage is the `has_face` gate and nothing
else. What is now open is precision: the lead holds 36 of 68 assignments.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The user checked the lead's crops. LIM SEONHO's 36 assignments cover at least
six different men, a chibi and a cat, so 36 of 68 is a bug. 22 came from
native resolves and 14 from reconcile merges.

Two fixes are written in the orchestrator repo, tested, not deployed and not
run on a GPU. `link_tracklets` caps a tracklet's panel span, because `window`
bounded each pair while transitivity was unbounded and the lead's 22 native
assignments came from tracklets spanning 22 and 30 panels. And one shared
appearance tokenizer drops generic words, because whole chains hung on the
word `short` and one pair on the word `hair`.

The obvious third fix is ruled out by measurement. Over all 22 crop
embeddings, the cat scores up to 0.82 against men, two different men score
0.93, and the highest pair is 0.96. No threshold separates them, so
crop-to-crop cosine is not a link signal.

Item 1 of the agreed plan, sending the live cast instead of a cosine top-k
gallery, is not started.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The gallery gemma chose from was the union of the tracklet members' cosine
shortlists. Cosine cannot separate people on this data, so a metric that
cannot tell two men apart decided who gemma was allowed to consider, and the
right character was often not on the list.

The gallery is now the live cast: gender-compatible rows from
get_known_characters, named first, capped, re-read per tracklet so a minted
character is visible to later ones. Every crop reaches the resolver now,
including one whose cosine top-k was empty; those used to be dropped.

worker_vision spreads reference images across a budget instead of sending 3
per candidate, so a 9-character cast costs 9 images and not 27.

Ran on a GPU, 19:44-19:52 UTC. The lead's assignments drop from 36 to 16 and
14 of the 16 are him; the other two are art inside a panel.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
merge_faceless_captions had been written and never called; both crop
endpoints called the non-destructive context_fragment_links instead, with no
decision recording that choice. Wiring it changes panel count and every panel
index, so the chapter needs a re-crop with the panels prefix cleared first --
crop_webtoon skips an upload when the key already exists, which is right for a
resume and silently wrong after a slicing change. Noted at the line.

It does not cover the head-in-one-shot body-in-the-next split that prompted
the question. _merge_plan only folds a fragment that has text and no face.

ARCHITECTURE.md is the target shape from the user's design, with what exists
against each section today. Nothing in it is built.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Magi and any learned head are ruled out, so every structure comes out of a
gemma prompt field or plain Python over gemma's output. Each section now
carries what exists today and a DoD.

The build order starts at step 0, the measurement spine: eval/chapter-truth.json
plus purity and fragmentation printed by audit_registry.py. Nothing below it is
measurable without that file.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
kami added 1 commit 2026-08-13 20:34:02 +02:00
The name is a shell fragment, `II, d[i+4:i+12]))\n"; done`, left by a
redirect in the A/V gap session and committed with 8113bdf. The file is
empty.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
kami requested changes 2026-08-13 20:41:52 +02:00
kami left a comment
Owner

couple of notes:

  • don't you think the tests being in the .py files with the implementation is a little ridiculous?
  • I think some of the workers need a little bit of polishing, cause the stale legacy we're building on top of.
  • why do we need X amount of workers being up with the tmux sessions? can't we have one orchestrator? this way it will be easier on both sides.
  • why don't you just move s3 uris to the constants with placeholders?
  • don't you think that some workers have a lot of the logic which is unused? is there a "deadcode" detector in python?
  • what's the regular CI/CD with python anyway? considering gitea is on the homesrv and workers mostly reside on workpc.
couple of notes: - don't you think the tests being in the .py files with the implementation is a little ridiculous? - I think some of the workers need a little bit of polishing, cause the stale legacy we're building on top of. - why do we need X amount of workers being up with the tmux sessions? can't we have one orchestrator? this way it will be easier on both sides. - why don't you just move s3 uris to the constants with placeholders? - don't you think that some workers have a lot of the logic which is unused? is there a "deadcode" detector in python? - what's the regular CI/CD with python anyway? considering gitea is on the homesrv and workers mostly reside on workpc.
@@ -0,0 +1,93 @@
"""Registry audit for one chapter, after vision + identity + reconcile and before anything downstream.
Owner

mind if we do some other static tests like this just to verify that rgw pipeline got the stuff right?

mind if we do some other static tests like this just to verify that rgw pipeline got the stuff right?
@@ -0,0 +1,38 @@
#!/usr/bin/env bash
Owner

this one and audits should probably be a part of the CICD pipeline.

this one and audits should probably be a part of the CICD pipeline.
kami added 1 commit 2026-08-13 21:02:14 +02:00
Five workers built output URIs with inline f-strings, so the bucket-per-artifact
layout was spread across worker_tts, worker_identity, worker_crop, worker_layers
and worker_render. Moving a class between buckets meant a grep. They are now
templates in transport.py, formatted at each call site.

Three of those workers also each reimplemented the same parse to recover
manga_id and chapter_id from an input uri, because the orchestrator does not
send them. That is transport.ids_from_uri now, and it raises on a uri too short
to carry the ids rather than returning a wrong pair.

ruff.toml makes `ruff check .` exit 0, so CI can gate on it and a new finding
means a new defect. Fixed: an implicit Optional in 8 signatures, an unparenthesized
implicit concatenation in the ASS filter list, 5 subprocess.run calls now saying
check=False out loud, an unused import, a duplicate exception handler and a
non-executable shebang. Every rule left off carries its reason in ruff.toml.

The ASYNC rules are off because ffmpeg on the event loop is real and already
recorded at caveats/audit-open.md#blocking-event-loop. It needs a refactor per
handler, not a lint fix.

Checked: transport, collage, bubble_detect, test_vision_parse, worker_crop,
worker_scene, worker_script, worker_identity, worker_tts, session_manager,
worker_vision and worker_render self-checks all pass. worker_layers still fails
on a missing legacy/qwen_layered_workflow.json, which predates this branch.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
kami added 1 commit 2026-08-13 21:06:41 +02:00
attic/worker_ocr.py and attic/worker_parse.py are 224 lines imported by nothing
and named in no doc. The OCR stage was removed when narration moved to the
director beat. The two design notes in attic/ stay, they are history.

worker_vision._panel_size had one reference and it was the definition.

The audit's larger finding is filed rather than fixed: call_gemma4,
_extract_json and _strip_thought exist in both worker_vision and worker_script
and have already diverged. That matters because the JSON repair pass can
fabricate dialogue, so a fix would land in one copy and not the other. It is
caveats/audit-open.md#gemma-helpers-duplicated with its revisit trigger.

HANDOFF.md carries the rest: _wrap2 against textwrap, the duplicated ONNX
preprocessing, and worker_layers pointing at a legacy/ directory that was never
tracked in git.

Checked: ruff clean, worker_vision and worker_render self-checks pass.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
claude merged commit a67f1c2501 into master 2026-08-13 21:07:14 +02:00
Sign in to join this conversation.
No Reviewers
No Label
2 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: kami/manga-recap-pipeline#1