comicbox.events

source module comicbox.events

Shared event types for read / write / online workflows.

One on_event callback shape across the three public bulk entry points (iter_process_files, bulk_write, OnlineSession.tag_many) so a caller — typically Codex — can wire a single handler.

Handlers run on the orchestrator thread that drains worker results. They must be thread-safe and should return quickly; expensive work belongs in a queue the handler dispatches to.

Attributes

  • SKIP_MATCHER_DECLINED : Final — declined them.

  • SKIP_QUOTA_RESERVED : Final — rather than record “this source found nothing for it”.

Classes

  • Event — Base for all workflow events.

  • BatchStarted — Fired once before the first file is submitted.

  • FileShortCircuited — Worker decided the embedded metadata had not changed and skipped parse.

  • FileParsed — Worker fully parsed embedded metadata.

  • FileError — Worker raised an exception. error is the str(exception).

  • BatchFinished — Fired once after every file has been delivered.

  • SourceStarted — Worker is about to consult one online source for this file.

  • SearchStarted — Worker is about to query an online source for this file.

  • SearchCompleted — Online source returned candidate list.

  • AutoWritten — Matcher accepted a candidate without prompting.

  • SeriesIdentified — A series was resolved and cached for series-first batching.

  • PromptQueued — Matcher needs human input; prompt dispatched to PromptHandler.

  • PromptResolved — PromptHandler returned a decision.

  • PromptDeferred — OnlineSession is in defer_prompts mode and queued this prompt for later.

  • PromptResolvedFromCache — OnlineSession auto-applied a cached choice instead of re-prompting.

  • Skipped — A source wrote no metadata for this file, and says why.

  • NoMatch — No candidate cleared min_confidence.

  • RateLimited — Source signaled a rate-limit hit.

  • FileFinished — Per-file online tagging completed (success, skip, no-match, or error).

source dataclass Event(*, kind: str, path: Path | None = None, index: int | None = None, total: int | None = None)

Base for all workflow events.

Subclasses are concrete frozen dataclasses keyed by the kind literal on the subclass — callers can match on type or on kind.

source dataclass BatchStarted(*, kind: Literal[‘batch_started’] = ‘batch_started’, path: Path | None = None, index: int | None = None, total: int | None = None)

Bases : Event

Fired once before the first file is submitted.

source dataclass FileShortCircuited(*, kind: Literal[‘file_short_circuited’] = ‘file_short_circuited’, path: Path | None = None, index: int | None = None, total: int | None = None, reason: Literal[‘mtime_unchanged’, ‘filtered’, ‘dry_run’] = ‘mtime_unchanged’)

Bases : Event

Worker decided the embedded metadata had not changed and skipped parse.

reason="mtime_unchanged" — embedded mtime <= caller’s old_mtime. reason="filtered" — caller passed full_metadata=False so the worker only collected envelope fields.

source dataclass FileParsed(*, kind: Literal[‘file_parsed’] = ‘file_parsed’, path: Path | None = None, index: int | None = None, total: int | None = None)

Bases : Event

Worker fully parsed embedded metadata.

source dataclass FileError(*, kind: Literal[‘file_error’] = ‘file_error’, path: Path | None = None, index: int | None = None, total: int | None = None, error: str = ‘’)

Bases : Event

Worker raised an exception. error is the str(exception).

source dataclass BatchFinished(*, kind: Literal[‘batch_finished’] = ‘batch_finished’, path: Path | None = None, index: int | None = None, total: int | None = None, parsed: int = 0, short_circuited: int = 0, errored: int = 0)

Bases : Event

Fired once after every file has been delivered.

parsed / short_circuited / errored carry per-outcome counts so callers can render an end-of-batch summary without re-walking the result stream.

source dataclass SourceStarted(*, kind: Literal[‘source_started’] = ‘source_started’, path: Path | None = None, index: int | None = None, total: int | None = None, source: str = ‘’)

Bases : Event

Worker is about to consult one online source for this file.

Fired once per source that actually runs, immediately before the source is consulted and after the first-wins skip — a source sat out because an earlier one already won never emits this. Unlike :class:SearchStarted, which only covers the cold-search path, this fires for every route a source can take: explicit-id fetch, stored-id refresh, series-cache issue lookup, and search. Callers rendering “which source is being consulted right now” want this one; SearchStarted stays the narrower “a full search is about to be issued” signal.

source dataclass SearchStarted(*, kind: Literal[‘search_started’] = ‘search_started’, path: Path | None = None, index: int | None = None, total: int | None = None, source: str = ‘’)

Bases : Event

Worker is about to query an online source for this file.

source dataclass SearchCompleted(*, kind: Literal[‘search_completed’] = ‘search_completed’, path: Path | None = None, index: int | None = None, total: int | None = None, source: str = ‘’, n_candidates: int = 0, top_score: float | None = None)

Bases : Event

Online source returned candidate list.

source dataclass AutoWritten(*, kind: Literal[‘auto_written’] = ‘auto_written’, path: Path | None = None, index: int | None = None, total: int | None = None, source: str = ‘’, candidate_summary: str = ‘’)

Bases : Event

Matcher accepted a candidate without prompting.

source dataclass SeriesIdentified(*, kind: Literal[‘series_identified’] = ‘series_identified’, path: Path | None = None, index: int | None = None, total: int | None = None, source: str = ‘’, series_fingerprint: str = ‘’, volume_id: int = 0)

Bases : Event

A series was resolved and cached for series-first batching.

Fired when a cold-path search resolves a series and the session’s series_cache is populated for the first time. Subsequent issues of the same series skip the search via :meth:OnlineSource.lookup_issue.

source dataclass PromptQueued(*, kind: Literal[‘prompt_queued’] = ‘prompt_queued’, path: Path | None = None, index: int | None = None, total: int | None = None, source: str = ‘’, prompt_id: str = ‘’, n_candidates: int = 0)

Bases : Event

Matcher needs human input; prompt dispatched to PromptHandler.

source dataclass PromptResolved(*, kind: Literal[‘prompt_resolved’] = ‘prompt_resolved’, path: Path | None = None, index: int | None = None, total: int | None = None, source: str = ‘’, prompt_id: str = ‘’, action: str = ‘’)

Bases : Event

PromptHandler returned a decision.

source dataclass PromptDeferred(*, kind: Literal[‘prompt_deferred’] = ‘prompt_deferred’, path: Path | None = None, index: int | None = None, total: int | None = None, source: str = ‘’, prompt_id: str = ‘’, fingerprint: str = ‘’, n_candidates: int = 0)

Bases : Event

OnlineSession is in defer_prompts mode and queued this prompt for later.

The batch continues; the deferred prompt is accessible via OnlineSession.deferred_prompts(). Codex’s intended flow: surface these in a “Review tagging” UI after the batch completes, collect the user’s decisions, seed them back into the session’s dedup cache via preload_resolution(), then re-run the affected files.

source dataclass PromptResolvedFromCache(*, kind: Literal[‘prompt_resolved_from_cache’] = ‘prompt_resolved_from_cache’, path: Path | None = None, index: int | None = None, total: int | None = None, source: str = ‘’, prompt_id: str = ‘’, action: str = ‘’, fingerprint: str = ‘’)

Bases : Event

OnlineSession auto-applied a cached choice instead of re-prompting.

Fingerprint matched a previously-resolved prompt in the per-session dedup cache; the user’s handler was not invoked.

source dataclass Skipped(*, kind: Literal[‘skipped’] = ‘skipped’, path: Path | None = None, index: int | None = None, total: int | None = None, source: str = ‘’, reason: str = ‘’)

Bases : Event

A source wrote no metadata for this file, and says why.

reason is one of the SKIP_* constants above.

source dataclass NoMatch(*, kind: Literal[‘no_match’] = ‘no_match’, path: Path | None = None, index: int | None = None, total: int | None = None, source: str = ‘’)

Bases : Event

No candidate cleared min_confidence.

source dataclass RateLimited(*, kind: Literal[‘rate_limited’] = ‘rate_limited’, path: Path | None = None, index: int | None = None, total: int | None = None, source: str = ‘’, retry_after_seconds: float | None = None)

Bases : Event

Source signaled a rate-limit hit.

retry_after_seconds is the server hint when available; otherwise the per-source retry-schedule’s next sleep.

source dataclass FileFinished(*, kind: Literal[‘file_finished’] = ‘file_finished’, path: Path | None = None, index: int | None = None, total: int | None = None, outcome: str = ‘’)

Bases : Event

Per-file online tagging completed (success, skip, no-match, or error).