* docs(plan-04): spec + plan for pipeline error transparency (#131)
speckit spec/plan/research/data-model/contract/quickstart for plan-04.
Grounds the fix in the real code map: shared failure-event builder
(backend/core/failure.py) feeding tasks.py + dub_pipeline.py + dub_core.py,
non-empty reason guarantee, sanitized diagnostic block, frontend renderer
with docs deeplink. Closes-target: #131 (children #122, #63).
Design only — no code changes yet.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* feat(pipeline): structured, non-empty failure events + logged tracebacks (#131)
plan-04 backend: no more silent "unknown error". A shared failure helper
guarantees a non-empty reason at every emit site and a sanitized,
copyable diagnostic block.
- backend/core/failure.py: build_failure()/build_failure_event() (reason
falls back to the exception class name), sanitize() (reuses the
logging_filter HF-token regex + redacts *TOKEN*/*KEY*/*SECRET* env values
+ home→~), diagnostic() (reuses the env capture), classify() reusing the
error_docs_map 5-class taxonomy for the docs deeplink + hint.
- core/tasks.py worker: structured event instead of bare str(e); keeps the
logged traceback.
- services/dub_pipeline.py: enrich download/extract error yields; ADD the
missing outer `except Exception` (the #122 path — unhandled ingest errors
were never surfaced with stage context); surface the previously-silent
demucs/scene/thumbnail degradations as non-fatal `warning` events.
- api/routers/batch.py: guaranteed non-empty batch failure reason.
SSE payload is additive (legacy `error`/`stage`/`detail` keys preserved),
so existing frontends keep working and already show the specific reason.
Tests (TDD, fail-before/pass-after): 14 cases — non-empty-reason guarantee,
redaction, diagnostic sanitization, and the 3 Test-matrix triggers
(worker / extract / url). 483 passed, 0 regressions.
Closes#131. Refs #122, #63.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* feat(dub-ui): show specific cause + docs deeplink + copyable diagnostic (#131)
plan-04 frontend. The backend now sends a structured, non-empty failure;
surface it to the user instead of "extract: unknown error".
- dubSlice: DubFailure type + dubFailure state/setter.
- useDubWorkflow: capture the structured failure on the SSE error event
(reason/error_class/stage/hint/docs_topic/diagnostic); clear on new runs.
- DubTab: DubFailureNotice renders the actionable hint, an "Open docs"
deeplink (via the existing errorDocsMap classifier), and a "Copy
diagnostic" button — shown beneath the error badge in both failure banners.
typecheck + build clean; 66 frontend tests pass.
Refs #131, #122, #63.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* fix(failure): annotate intentional best-effort excepts (CodeQL)
The new security workflow's CodeQL flagged 5 bare `except: pass` blocks.
All are deliberate best-effort guards (sanitize/diagnostic must never throw
on the failure path; the test cancels the worker to tear it down). Added
explanatory comments per CodeQL's py/empty-except rule. No behavior change.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>